ntminer 4 年 前
コミット
7f025f2c5e
100 ファイル変更18118 行追加11986 行削除
  1. 14 0
      NTMiner.sln
  2. 0 1
      src/AppModels/MinerStudio/Vms/MinerClientsWindowViewModel.cs
  3. 58 0
      src/AppModels/MinerStudio/Vms/WebApiServerStateViewModel.cs
  4. 30 0
      src/AppModels/MinerStudio/Vms/WsServerNodeStateViewModel.cs
  5. 0 7
      src/AppViews0/AppViews0.csproj
  6. 2 2
      src/AppViews0/MinerStudio/Views/MinerClientsWindow.xaml.cs
  7. 54 23
      src/AppViews0/MinerStudio/Views/Ucs/WsServerNodePage.xaml
  8. 0 1
      src/AppViews0/Views/Ucs/Toolbox.xaml
  9. 4 1
      src/MinerClient/App.xaml.cs
  10. 9 0
      src/MinerClient/MinerClient.csproj
  11. 0 0
      src/MinerClient/SplashWindow.xaml
  12. 0 0
      src/MinerClient/SplashWindow.xaml.cs
  13. 1 0
      src/MinerStudio/App.xaml.cs
  14. 4 3
      src/MinerStudio/MinerStudio.csproj
  15. 1 1
      src/NTMinerClient/Mine/Cleaner.cs
  16. 1 1
      src/NTMinerClient/Mine/MineContext.cs
  17. 4 3
      src/NTMinerDaemon/NTMinerDaemon.csproj
  18. 1 1
      src/NTMinerDaemon/Ws/AbstractWsClient.cs
  19. 1 1
      src/NTMinerDataSchemas/NTKeyword.cs
  20. 2 0
      src/NTMinerDataSchemas/ServerNode/IVarServerState.cs
  21. 2 0
      src/NTMinerDataSchemas/ServerNode/WebApiServerState.cs
  22. 2 0
      src/NTMinerDataSchemas/ServerNode/WsServerNodeState.cs
  23. 112 114
      src/NTMinerHub/Hub/MessagePathHub.cs
  24. 27 0
      src/NTMinerNoDevFee/VirtualRoot.cs
  25. 4 16
      src/NTMinerlib/TempPath.cs
  26. 45 25
      src/NTMinerlib/VirtualRoot.partials.Common.cs
  27. 1 1
      src/NTMinerlib/Windows/Cpu.cs
  28. BIN
      src/ThirdPartyDlls/websocket-sharp.dll
  29. 0 11730
      src/ThirdPartyDlls/websocket-sharp.xml
  30. 10 1
      src/UnitTests/RamTests.cs
  31. 14 0
      src/UnitTests/ReflectionTests.cs
  32. 20 0
      src/UnitTests/ShardingHasherTests.cs
  33. 1 1
      src/UserServer/AppRoot.cs
  34. 4 3
      src/UserServer/UserServer.csproj
  35. 3 1
      src/WebApiServer/AppRoot.cs
  36. 5 2
      src/WsServer/Core/ISession.cs
  37. 7 1
      src/WsServer/Core/Impl/AbstractSession.cs
  38. 4 9
      src/WsServer/Core/Impl/AbstractSessionSet`1.cs
  39. 2 1
      src/WsServer/Core/Impl/MinerClientSessionSet.cs
  40. 6 0
      src/WsServer/Core/Impl/MinerSignSet.cs
  41. 38 32
      src/WsServer/Core/Impl/WsServerNodeAddressSet.cs
  42. 4 3
      src/WsServer/WsServer.csproj
  43. 1 1
      src/WsServer/WsSharp/SharpWsServerAdapter.cs
  44. 26 0
      src/websocket-sharp/AssemblyInfo.cs
  45. 47 0
      src/websocket-sharp/ByteOrder.cs
  46. 113 0
      src/websocket-sharp/CloseEventArgs.cs
  47. 120 0
      src/websocket-sharp/CloseStatusCode.cs
  48. 52 0
      src/websocket-sharp/CompressionMethod.cs
  49. 109 0
      src/websocket-sharp/ErrorEventArgs.cs
  50. 2146 0
      src/websocket-sharp/Ext.cs
  51. 51 0
      src/websocket-sharp/Fin.cs
  52. 208 0
      src/websocket-sharp/HttpBase.cs
  53. 217 0
      src/websocket-sharp/HttpRequest.cs
  54. 209 0
      src/websocket-sharp/HttpResponse.cs
  55. 149 0
      src/websocket-sharp/LogData.cs
  56. 63 0
      src/websocket-sharp/LogLevel.cs
  57. 330 0
      src/websocket-sharp/Logger.cs
  58. 51 0
      src/websocket-sharp/Mask.cs
  59. 183 0
      src/websocket-sharp/MessageEventArgs.cs
  60. 151 0
      src/websocket-sharp/Net/AuthenticationBase.cs
  61. 146 0
      src/websocket-sharp/Net/AuthenticationChallenge.cs
  62. 323 0
      src/websocket-sharp/Net/AuthenticationResponse.cs
  63. 66 0
      src/websocket-sharp/Net/AuthenticationSchemes.cs
  64. 91 0
      src/websocket-sharp/Net/Chunk.cs
  65. 360 0
      src/websocket-sharp/Net/ChunkStream.cs
  66. 213 0
      src/websocket-sharp/Net/ChunkedRequestStream.cs
  67. 303 0
      src/websocket-sharp/Net/ClientSslConfiguration.cs
  68. 1016 0
      src/websocket-sharp/Net/Cookie.cs
  69. 821 0
      src/websocket-sharp/Net/CookieCollection.cs
  70. 165 0
      src/websocket-sharp/Net/CookieException.cs
  71. 582 0
      src/websocket-sharp/Net/EndPointListener.cs
  72. 261 0
      src/websocket-sharp/Net/EndPointManager.cs
  73. 82 0
      src/websocket-sharp/Net/HttpBasicIdentity.cs
  74. 617 0
      src/websocket-sharp/Net/HttpConnection.cs
  75. 187 0
      src/websocket-sharp/Net/HttpDigestIdentity.cs
  76. 128 0
      src/websocket-sharp/Net/HttpHeaderInfo.cs
  77. 44 0
      src/websocket-sharp/Net/HttpHeaderType.cs
  78. 836 0
      src/websocket-sharp/Net/HttpListener.cs
  79. 198 0
      src/websocket-sharp/Net/HttpListenerAsyncResult.cs
  80. 340 0
      src/websocket-sharp/Net/HttpListenerContext.cs
  81. 127 0
      src/websocket-sharp/Net/HttpListenerException.cs
  82. 273 0
      src/websocket-sharp/Net/HttpListenerPrefix.cs
  83. 299 0
      src/websocket-sharp/Net/HttpListenerPrefixCollection.cs
  84. 959 0
      src/websocket-sharp/Net/HttpListenerRequest.cs
  85. 1243 0
      src/websocket-sharp/Net/HttpListenerResponse.cs
  86. 233 0
      src/websocket-sharp/Net/HttpRequestHeader.cs
  87. 189 0
      src/websocket-sharp/Net/HttpResponseHeader.cs
  88. 346 0
      src/websocket-sharp/Net/HttpStatusCode.cs
  89. 184 0
      src/websocket-sharp/Net/HttpStreamAsyncResult.cs
  90. 1150 0
      src/websocket-sharp/Net/HttpUtility.cs
  91. 73 0
      src/websocket-sharp/Net/HttpVersion.cs
  92. 52 0
      src/websocket-sharp/Net/InputChunkState.cs
  93. 49 0
      src/websocket-sharp/Net/InputState.cs
  94. 50 0
      src/websocket-sharp/Net/LineState.cs
  95. 209 0
      src/websocket-sharp/Net/NetworkCredential.cs
  96. 150 0
      src/websocket-sharp/Net/QueryStringCollection.cs
  97. 124 0
      src/websocket-sharp/Net/ReadBufferState.cs
  98. 267 0
      src/websocket-sharp/Net/RequestStream.cs
  99. 403 0
      src/websocket-sharp/Net/ResponseStream.cs
  100. 236 0
      src/websocket-sharp/Net/ServerSslConfiguration.cs

+ 14 - 0
NTMiner.sln

@@ -118,6 +118,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{103F58A8-D0E
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserServer", "src\UserServer\UserServer.csproj", "{7141D542-E321-406D-A242-B857255F79F6}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "src\websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -464,6 +466,18 @@ Global
 		{7141D542-E321-406D-A242-B857255F79F6}.Release|x64.Build.0 = Release|Any CPU
 		{7141D542-E321-406D-A242-B857255F79F6}.Release|x86.ActiveCfg = Release|Any CPU
 		{7141D542-E321-406D-A242-B857255F79F6}.Release|x86.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}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|x64.Build.0 = Debug|Any CPU
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|x86.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
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|x64.ActiveCfg = Release|Any CPU
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|x64.Build.0 = Release|Any CPU
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|x86.ActiveCfg = Release|Any CPU
+		{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 1
src/AppModels/MinerStudio/Vms/MinerClientsWindowViewModel.cs

@@ -445,7 +445,6 @@ namespace NTMiner.MinerStudio.Vms {
                                             item.OnPropertyChanged(nameof(item.WorkerName));
                                         }
                                     }
-                                    // TODO:考虑是否应该只刷新选中的矿机以消减网络流量
                                     QueryMinerClients();
                                 }
                             });

+ 58 - 0
src/AppModels/MinerStudio/Vms/WebApiServerStateViewModel.cs

@@ -13,6 +13,8 @@ namespace NTMiner.MinerStudio.Vms {
         private double _cpuPerformance;
         private ulong _availablePhysicalMemory;
         private double _processMemoryMb;
+        private long _threadCount;
+        private long _handleCount;
         private CpuData _cpu;
         private CpuDataViewModel _cpuVm;
         private List<WsServerNodeState> _wsServerNodes;
@@ -26,6 +28,8 @@ namespace NTMiner.MinerStudio.Vms {
             _cpuPerformance = data.CpuPerformance;
             _availablePhysicalMemory = data.AvailablePhysicalMemory;
             _processMemoryMb = data.ProcessMemoryMb;
+            _threadCount = data.ThreadCount;
+            _handleCount = data.HandleCount;
             _cpu = data.Cpu;
             _cpuVm = new CpuDataViewModel(data.Cpu);
             _wsServerNodes = data.WsServerNodes;
@@ -40,6 +44,8 @@ namespace NTMiner.MinerStudio.Vms {
             this.CpuPerformance = data.CpuPerformance;
             this.AvailablePhysicalMemory = data.AvailablePhysicalMemory;
             this.ProcessMemoryMb = data.ProcessMemoryMb;
+            this.ThreadCount = data.ThreadCount;
+            this.HandleCount = data.HandleCount;
             this.Cpu = data.Cpu;
             this.WsServerNodes = data.WsServerNodes;
         }
@@ -71,6 +77,10 @@ namespace NTMiner.MinerStudio.Vms {
                         }
                     }
                 }
+                OnPropertyChanged(nameof(MinerClientWsSessionCount));
+                OnPropertyChanged(nameof(MinerClientSessionCount));
+                OnPropertyChanged(nameof(MinerStudioWsSessionCount));
+                OnPropertyChanged(nameof(MinerStudioSessionCount));
             }
         }
 
@@ -80,6 +90,30 @@ namespace NTMiner.MinerStudio.Vms {
             }
         }
 
+        public int MinerClientWsSessionCount {
+            get {
+                return WsServerNodeVms.Sum(a => a.MinerClientWsSessionCount);
+            }
+        }
+
+        public int MinerClientSessionCount {
+            get {
+                return WsServerNodeVms.Sum(a => a.MinerClientSessionCount);
+            }
+        }
+
+        public int MinerStudioWsSessionCount {
+            get {
+                return WsServerNodeVms.Sum(a => a.MinerStudioWsSessionCount);
+            }
+        }
+
+        public int MinerStudioSessionCount {
+            get {
+                return WsServerNodeVms.Sum(a => a.MinerStudioSessionCount);
+            }
+        }
+
         public string Description {
             get => _description;
             set {
@@ -185,5 +219,29 @@ namespace NTMiner.MinerStudio.Vms {
                 return this.ProcessMemoryMb.ToString("f1") + " Mb";
             }
         }
+
+        public long ThreadCount {
+            get {
+                return _threadCount;
+            }
+            set {
+                if (_threadCount != value) {
+                    _threadCount = value;
+                    OnPropertyChanged(nameof(ThreadCount));
+                }
+            }
+        }
+
+        public long HandleCount {
+            get {
+                return _handleCount;
+            }
+            set {
+                if (_handleCount != value) {
+                    _handleCount = value;
+                    OnPropertyChanged(nameof(HandleCount));
+                }
+            }
+        }
     }
 }

+ 30 - 0
src/AppModels/MinerStudio/Vms/WsServerNodeStateViewModel.cs

@@ -15,6 +15,8 @@ namespace NTMiner.MinerStudio.Vms {
         private double _cpuPerformance;
         private ulong _availablePhysicalMemory;
         private double _processMemoryMb;
+        private long _threadCount;
+        private long _handleCount;
         private CpuData _cpu;
         private CpuDataViewModel _cpuVm;
 
@@ -37,6 +39,8 @@ namespace NTMiner.MinerStudio.Vms {
             _availablePhysicalMemory = data.AvailablePhysicalMemory;
             _cpuPerformance = data.CpuPerformance;
             _processMemoryMb = data.ProcessMemoryMb;
+            _threadCount = data.ThreadCount;
+            _handleCount = data.HandleCount;
             _cpu = data.Cpu;
             _cpuVm = new CpuDataViewModel(data.Cpu);
         }
@@ -52,6 +56,8 @@ namespace NTMiner.MinerStudio.Vms {
             this.CpuPerformance = data.CpuPerformance;
             this.AvailablePhysicalMemory = data.AvailablePhysicalMemory;
             this.ProcessMemoryMb = data.ProcessMemoryMb;
+            this.ThreadCount = data.ThreadCount;
+            this.HandleCount = data.HandleCount;
         }
 
         public string Address {
@@ -199,5 +205,29 @@ namespace NTMiner.MinerStudio.Vms {
                 return this.ProcessMemoryMb.ToString("f1") + " Mb";
             }
         }
+
+        public long ThreadCount {
+            get {
+                return _threadCount;
+            }
+            set {
+                if (_threadCount != value) {
+                    _threadCount = value;
+                    OnPropertyChanged(nameof(ThreadCount));
+                }
+            }
+        }
+
+        public long HandleCount {
+            get {
+                return _handleCount;
+            }
+            set {
+                if (_handleCount != value) {
+                    _handleCount = value;
+                    OnPropertyChanged(nameof(HandleCount));
+                }
+            }
+        }
     }
 }

+ 0 - 7
src/AppViews0/AppViews0.csproj

@@ -118,9 +118,6 @@
     <Compile Include="Views\PackagesWindow.xaml.cs">
       <DependentUpon>PackagesWindow.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Views\SplashWindow.xaml.cs">
-      <DependentUpon>SplashWindow.xaml</DependentUpon>
-    </Compile>
     <Compile Include="MinerStudio\Views\Ucs\MinerClientOperationResults.xaml.cs">
       <DependentUpon>MinerClientOperationResults.xaml</DependentUpon>
     </Compile>
@@ -699,10 +696,6 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
-    <Page Include="Views\SplashWindow.xaml">
-      <Generator>MSBuild:Compile</Generator>
-      <SubType>Designer</SubType>
-    </Page>
     <Page Include="MinerStudio\Views\Ucs\MinerClientOperationResults.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>

+ 2 - 2
src/AppViews0/MinerStudio/Views/MinerClientsWindow.xaml.cs

@@ -142,8 +142,8 @@ namespace NTMiner.MinerStudio.Views {
                         foreach (var item in minerClients) {
                             item.OnPropertyChanged(nameof(item.LastActivedOnText));
                         }
-                        if (RpcRoot.IsOuterNet && Vm.CountDown == 5) {
-                            // 外网群控时在矿机列表页数据刷新前5秒通过Ws刷新矿机的算力数据
+                        if (RpcRoot.IsOuterNet && Vm.CountDown == 2) {
+                            // 外网群控时在矿机列表页数据刷新前2秒通过Ws刷新矿机的算力数据
                             MinerStudioRoot.WsClient.SendAsync(new WsMessage(Guid.NewGuid(), WsMessage.GetSpeed) {
                                 Data = Vm.MinerClients.Select(a => a.ClientId).ToList()
                             });

+ 54 - 23
src/AppViews0/MinerStudio/Views/Ucs/WsServerNodePage.xaml

@@ -11,15 +11,15 @@
     Background="White"
 	mc:Ignorable="d" 
     d:DesignHeight="400" 
-    d:DesignWidth="1600"
+    d:DesignWidth="1800"
     d:DataContext="{d:DesignData Source=../Design/WsServerNodePageViewModel.xaml}">
     <UserControl.Resources>
         <Style x:Key="LblTb" TargetType="TextBlock" BasedOn="{StaticResource LblTbBase}">
-            <Setter Property="Width" Value="100"></Setter>
+            <Setter Property="Width" Value="80"></Setter>
             <Setter Property="TextAlignment" Value="Left"></Setter>
         </Style>
         <Style x:Key="TextBlock" TargetType="TextBlock">
-            <Setter Property="Width" Value="200"></Setter>
+            <Setter Property="Width" Value="150"></Setter>
             <Setter Property="VerticalAlignment" Value="Center"></Setter>
         </Style>
     </UserControl.Resources>
@@ -29,36 +29,39 @@
             <RowDefinition Height="*"></RowDefinition>
         </Grid.RowDefinitions>
         <StackPanel>
-            <WrapPanel>
+            <WrapPanel Margin="4">
                 <TextBlock Style="{StaticResource LblTb}">节点地址</TextBlock>
                 <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.Address}"></TextBlock>
                 <TextBlock Style="{StaticResource LblTb}">进程内存</TextBlock>
                 <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.ProcessMemoryMbText}"></TextBlock>
+                <TextBlock Style="{StaticResource LblTb}">线程数</TextBlock>
+                <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.ThreadCount}"></TextBlock>
+                <TextBlock Style="{StaticResource LblTb}">句柄数</TextBlock>
+                <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.HandleCount}"></TextBlock>
                 <TextBlock Style="{StaticResource LblTb}">总内存</TextBlock>
                 <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.TotalPhysicalMemory,Converter={StaticResource ByteToGbConverter}}"></TextBlock>
-                <TextBlock Style="{StaticResource LblTb}">剩余内存</TextBlock>
-                <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.AvailablePhysicalMemory,Converter={StaticResource ByteToGbConverter}}"></TextBlock>
+                <TextBlock Style="{StaticResource LblTb}">操作系统</TextBlock>
+                <TextBlock Width="300" Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.OSInfo}"></TextBlock>
             </WrapPanel>
-            <WrapPanel>
-                <TextBlock Style="{StaticResource LblTb}">CPU使用率</TextBlock>
-                <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.CpuPerformanceText}"></TextBlock>
+            <WrapPanel Margin="4 0 4 4">
                 <TextBlock Style="{StaticResource LblTb}">CPU核数</TextBlock>
                 <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.Cpu.NumberOfLogicalCores}"></TextBlock>
                 <TextBlock Style="{StaticResource LblTb}">CPU主频</TextBlock>
                 <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.Cpu.ClockSpeed}"></TextBlock>
-            </WrapPanel>
-            <WrapPanel>
                 <TextBlock Style="{StaticResource LblTb}">CPU架构</TextBlock>
                 <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.Cpu.ProcessorArchitecture}"></TextBlock>
+                <TextBlock Style="{StaticResource LblTb}">CPU使用率</TextBlock>
+                <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.CpuPerformanceText}"></TextBlock>
+                <TextBlock Style="{StaticResource LblTb}">剩余内存</TextBlock>
+                <TextBlock Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.AvailablePhysicalMemory,Converter={StaticResource ByteToGbConverter}}"></TextBlock>
                 <TextBlock Style="{StaticResource LblTb}">CPU名称</TextBlock>
                 <TextBlock Width="300" Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.Cpu.Name}"></TextBlock>
-                <TextBlock Style="{StaticResource LblTb}">操作系统</TextBlock>
-                <TextBlock Width="300" Style="{StaticResource TextBlock}" Text="{Binding WebApiServerStateVm.OSInfo}"></TextBlock>
             </WrapPanel>
         </StackPanel>
 		<DataGrid 
             Grid.Row="1"
 			Margin="0" 
+			ColumnHeaderHeight="32"
             ItemsSource="{Binding WebApiServerStateVm.WsServerNodeVms}" 
 			BorderThickness="0 1 0 0"
             BorderBrush="{StaticResource LightLineColor}">
@@ -68,31 +71,59 @@
 			<DataGrid.Columns>
 				<DataGridTextColumn IsReadOnly="True" Width="140" Header="节点地址" Binding="{Binding Address}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="100" Header="挖矿端Ws会话数" Binding="{Binding MinerClientWsSessionCount}">
+                <DataGridTextColumn IsReadOnly="True" Width="100" Binding="{Binding MinerClientWsSessionCount}">
+                    <DataGridTextColumn.Header>
+                        <StackPanel>
+                            <TextBlock>挖矿端Ws会话数</TextBlock>
+                            <TextBlock Text="{Binding Data.WebApiServerStateVm.MinerClientWsSessionCount,Source={StaticResource proxy}}"></TextBlock>
+                        </StackPanel>
+                    </DataGridTextColumn.Header>
+                </DataGridTextColumn>
+                <DataGridTextColumn IsReadOnly="True" Width="80" Binding="{Binding MinerClientSessionCount}">
+                    <DataGridTextColumn.Header>
+                        <StackPanel>
+                            <TextBlock>挖矿端会话数</TextBlock>
+                            <TextBlock Text="{Binding Data.WebApiServerStateVm.MinerClientSessionCount,Source={StaticResource proxy}}"></TextBlock>
+                        </StackPanel>
+                    </DataGridTextColumn.Header>
+                </DataGridTextColumn>
+                <DataGridTextColumn IsReadOnly="True" Width="124" Binding="{Binding MinerStudioWsSessionCount}">
+                    <DataGridTextColumn.Header>
+                        <StackPanel>
+                            <TextBlock>群控客户端Ws会话数</TextBlock>
+                            <TextBlock Text="{Binding Data.WebApiServerStateVm.MinerStudioWsSessionCount,Source={StaticResource proxy}}"></TextBlock>
+                        </StackPanel>
+                    </DataGridTextColumn.Header>
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="100" Header="挖矿端会话数" Binding="{Binding MinerClientSessionCount}">
+                <DataGridTextColumn IsReadOnly="True" Width="106" Binding="{Binding MinerStudioSessionCount}">
+                    <DataGridTextColumn.Header>
+                        <StackPanel>
+                            <TextBlock>群控客户端会话数</TextBlock>
+                            <TextBlock Text="{Binding Data.WebApiServerStateVm.MinerStudioSessionCount,Source={StaticResource proxy}}"></TextBlock>
+                        </StackPanel>
+                    </DataGridTextColumn.Header>
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="124" Header="群控客户端Ws会话数" Binding="{Binding MinerStudioWsSessionCount}">
+                <DataGridTextColumn IsReadOnly="True" Width="70" Header="进程内存" Binding="{Binding ProcessMemoryMbText}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="106" Header="群控客户端会话数" Binding="{Binding MinerStudioSessionCount}">
+                <DataGridTextColumn IsReadOnly="True" Width="50" Header="线程数" Binding="{Binding ThreadCount}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="90" Header="进程内存" Binding="{Binding ProcessMemoryMbText}">
+                <DataGridTextColumn IsReadOnly="True" Width="50" Header="句柄数" Binding="{Binding HandleCount}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="90" Header="总内存" Binding="{Binding TotalPhysicalMemory,Converter={StaticResource ByteToGbConverter}}">
+                <DataGridTextColumn IsReadOnly="True" Width="60" Header="总内存" Binding="{Binding TotalPhysicalMemory,Converter={StaticResource ByteToGbConverter}}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="90" Header="剩余内存" Binding="{Binding AvailablePhysicalMemory,Converter={StaticResource ByteToGbConverter}}">
+                <DataGridTextColumn IsReadOnly="True" Width="60" Header="剩余内存" Binding="{Binding AvailablePhysicalMemory,Converter={StaticResource ByteToGbConverter}}">
                 </DataGridTextColumn>
                 <DataGridTextColumn IsReadOnly="True" Width="70" Header="CPU使用率" Binding="{Binding CpuPerformanceText}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="290" Header="CPU名称" Binding="{Binding CpuVm.Name}">
+                <DataGridTextColumn IsReadOnly="True" Width="306" Header="CPU名称" Binding="{Binding CpuVm.Name}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="70" Header="CPU核数" Binding="{Binding CpuVm.NumberOfLogicalCores}">
+                <DataGridTextColumn IsReadOnly="True" Width="60" Header="CPU核数" Binding="{Binding CpuVm.NumberOfLogicalCores}">
                 </DataGridTextColumn>
                 <DataGridTextColumn IsReadOnly="True" Width="70" Header="CPU主频" Binding="{Binding CpuVm.ClockSpeed}">
                 </DataGridTextColumn>
                 <DataGridTextColumn IsReadOnly="True" Width="60" Header="CPU架构" Binding="{Binding CpuVm.ProcessorArchitecture}">
                 </DataGridTextColumn>
-                <DataGridTextColumn IsReadOnly="True" Width="290" Header="操作系统" Binding="{Binding OSInfo}">
+                <DataGridTextColumn IsReadOnly="True" Width="280" Header="操作系统" Binding="{Binding OSInfo}">
                 </DataGridTextColumn>
                 <DataGridTextColumn Width="*" IsReadOnly="True" Header="备注" Binding="{Binding Description}">
 				</DataGridTextColumn>

+ 0 - 1
src/AppViews0/Views/Ucs/Toolbox.xaml

@@ -232,7 +232,6 @@
 					Width="{StaticResource ItemWidth}"
 					Margin="4"
                     KbButtonHoverBackground="{StaticResource KbButtonHoverBackground}"
-					IsEnabled="{Binding IsAutoAdminLogon,Converter={StaticResource BoolInvertConverter}}"
 					Command="{Binding WindowsAutoLogon}"
 					Cursor="Hand"
 					Background="Transparent">

+ 4 - 1
src/MinerClient/App.xaml.cs

@@ -20,11 +20,12 @@ namespace NTMiner {
         public static readonly string BlockWAUFileFullName = Path.Combine(TempPath.TempDirFullName, BlockWAUResourceName);
 
         public App() {
+            Hub.MessagePathHub.SetNotifyProperty();
             if ((NTMinerRegistry.GetIsAutoStart() || CommandLineArgs.IsAutoStart) && NTMinerRegistry.GetIsNoUi()) {
                 NTMinerConsole.Disable();
             }
             VirtualRoot.SetOut(NotiCenterWindowViewModel.Instance);
-            Logger.SetDir(TempPath.LogsDirFullName);
+            Logger.SetDir(TempPath.TempLogsDirFullName);
             WpfUtil.Init();
             AppUtil.Init(this);
             AppUtil.IsHotKeyEnabled = true;
@@ -303,6 +304,8 @@ namespace NTMiner {
             #region 启用或禁用windows开机自动登录
             VirtualRoot.BuildCmdPath<EnableOrDisableWindowsAutoLoginCommand>(path: message => {
                 if (NTMiner.Windows.OS.Instance.IsAutoAdminLogon) {
+                    VirtualRoot.Execute(new UnTopmostCommand());
+                    NTMiner.Windows.Cmd.RunClose("control", "userpasswords2");
                     return;
                 }
                 if (NTMiner.Windows.OS.Instance.IsGEWindows2004) {

+ 9 - 0
src/MinerClient/MinerClient.csproj

@@ -115,6 +115,9 @@
   <ItemGroup>
     <Compile Include="App.xaml.cs" />
     <Compile Include="NoDevFee\NoDevFeeUtil.cs" />
+    <Compile Include="SplashWindow.xaml.cs">
+      <DependentUpon>SplashWindow.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Windows\WindowsUtil.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -209,6 +212,12 @@
   <ItemGroup>
     <EmbeddedResource Include="NoDevFee\NTMinerNoDevFee.exe" />
   </ItemGroup>
+  <ItemGroup>
+    <Page Include="SplashWindow.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
     <PropertyGroup>

+ 0 - 0
src/AppViews0/Views/SplashWindow.xaml → src/MinerClient/SplashWindow.xaml


+ 0 - 0
src/AppViews0/Views/SplashWindow.xaml.cs → src/MinerClient/SplashWindow.xaml.cs


+ 1 - 0
src/MinerStudio/App.xaml.cs

@@ -11,6 +11,7 @@ using System.Windows;
 namespace NTMiner {
     public partial class App : Application {
         public App() {
+            Hub.MessagePathHub.SetNotifyProperty();
             // 群控客户端独立一个子目录,从而挖矿客户端和群控客户端放在同一个目录时避免路径重复。
             HomePath.SetHomeDirFullName(System.IO.Path.Combine(HomePath.AppDomainBaseDirectory, "NTMiner"));
             VirtualRoot.SetOut(NotiCenterWindowViewModel.Instance);

+ 4 - 3
src/MinerStudio/MinerStudio.csproj

@@ -117,9 +117,6 @@
     <Reference Include="System.Xaml">
       <RequiredTargetFramework>4.0</RequiredTargetFramework>
     </Reference>
-    <Reference Include="websocket-sharp">
-      <HintPath>..\ThirdPartyDlls\websocket-sharp.dll</HintPath>
-    </Reference>
     <Reference Include="WindowsBase" />
     <Reference Include="PresentationCore" />
     <Reference Include="PresentationFramework" />
@@ -188,6 +185,10 @@
       <Project>{dd8e010e-d5e9-47cf-9cb4-8dc6e13d483d}</Project>
       <Name>NTMinerWpf</Name>
     </ProjectReference>
+    <ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
+      <Project>{b357bac7-529e-4d81-a0d2-71041b19c8de}</Project>
+      <Name>websocket-sharp</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <Resource Include="logo.ico" />

+ 1 - 1
src/NTMinerClient/Mine/Cleaner.cs

@@ -102,7 +102,7 @@ namespace NTMiner.Mine {
         private void ClearLogs() {
             try {
                 List<string> toRemoves = new List<string>();
-                foreach (var file in Directory.GetFiles(TempPath.LogsDirFullName)) {
+                foreach (var file in Directory.GetFiles(TempPath.TempLogsDirFullName)) {
                     FileInfo fileInfo = new FileInfo(file);
                     if (fileInfo.LastWriteTime.AddDays(7) < DateTime.Now) {
                         toRemoves.Add(file);

+ 1 - 1
src/NTMinerClient/Mine/MineContext.cs

@@ -73,7 +73,7 @@ namespace NTMiner.Mine {
                 this.KernelProcessType = KernelProcessType.Pip;
                 logFileName = $"{this.Kernel.Code}_pip_{DateTime.Now.Ticks.ToString()}.log";
             }
-            this.LogFileFullName = Path.Combine(TempPath.LogsDirFullName, logFileName);
+            this.LogFileFullName = Path.Combine(TempPath.TempLogsDirFullName, logFileName);
         }
 
         public void Start(bool isRestart) {

+ 4 - 3
src/NTMinerDaemon/NTMinerDaemon.csproj

@@ -79,9 +79,6 @@
     <Reference Include="System.Web.Http.SelfHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
       <HintPath>..\..\packages\Microsoft.AspNet.WebApi.SelfHost.4.0.30506.0\lib\net40\System.Web.Http.SelfHost.dll</HintPath>
     </Reference>
-    <Reference Include="websocket-sharp">
-      <HintPath>..\ThirdPartyDlls\websocket-sharp.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\AppModels\RemoteDesktop\Firewall.cs">
@@ -202,6 +199,10 @@
       <Project>{c7108d8f-eb73-4ae3-916f-be817ede37af}</Project>
       <Name>NTMinerRpcClient</Name>
     </ProjectReference>
+    <ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
+      <Project>{b357bac7-529e-4d81-a0d2-71041b19c8de}</Project>
+      <Name>websocket-sharp</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="logo.ico" />

+ 1 - 1
src/NTMinerDaemon/Ws/AbstractWsClient.cs

@@ -252,7 +252,7 @@ namespace NTMiner.Ws {
                             var ws = new WebSocket($"ws://{server}/{_appType.GetName()}") {
                                 Compression = CompressionMethod.Deflate
                             };
-                            ws.Log.File = TempPath.WebSocketSharpMinerClientLogFileFullName;
+                            ws.Log.File = System.IO.Path.Combine(TempPath.TempLogsDirFullName, NTKeyword.WebSocketSharpMinerClientLogFileName);
                             ws.Log.Output = WebSocketSharpOutput;
                             ws.OnOpen += new EventHandler(Ws_OnOpen);
                             ws.OnMessage += new EventHandler<MessageEventArgs>(Ws_OnMessage);

+ 1 - 1
src/NTMinerDataSchemas/NTKeyword.cs

@@ -23,7 +23,7 @@ namespace NTMiner {
         public const string RootLockFileName = "home.lock";
         public const string RootConfigFileName = "home.config";
 
-        public const string LogsDirName = "Logs";
+        public const string LogsDirName = "logs";
         public const string WebSocketSharpMinerClientLogFileName = "websocket-sharp-minerclient.log";
         public const string WebSocketSharpMinerStudioLogFileName = "websocket-sharp-minerstudio.log";
         public const string ServerJsonFileName = "server.json";

+ 2 - 0
src/NTMinerDataSchemas/ServerNode/IVarServerState.cs

@@ -19,5 +19,7 @@
         /// 本进程所用内存
         /// </summary>
         double ProcessMemoryMb { get; }
+        long ThreadCount { get; }
+        long HandleCount { get; }
     }
 }

+ 2 - 0
src/NTMinerDataSchemas/ServerNode/WebApiServerState.cs

@@ -26,5 +26,7 @@ namespace NTMiner.ServerNode {
         public ulong AvailablePhysicalMemory { get; set; }
 
         public double ProcessMemoryMb { get; set; }
+        public long ThreadCount { get; set; }
+        public long HandleCount { get; set; }
     }
 }

+ 2 - 0
src/NTMinerDataSchemas/ServerNode/WsServerNodeState.cs

@@ -26,6 +26,8 @@ namespace NTMiner.ServerNode {
 
         public ulong AvailablePhysicalMemory { get; set; }
         public double ProcessMemoryMb { get; set; }
+        public long ThreadCount { get; set; }
+        public long HandleCount { get; set; }
 
         public StringBuilder GetSignData() {
             return this.GetActionIdSign("F9C674C1-247D-45DF-984A-2180AD76F2BB");

+ 112 - 114
src/NTMinerHub/Hub/MessagePathHub.cs

@@ -1,14 +1,116 @@
 namespace NTMiner.Hub {
     using System;
     using System.Collections.Generic;
-#if DEBUG
     using System.ComponentModel;
-#endif
     using System.Linq;
     using System.Threading;
 
     public class MessagePathHub : IMessagePathHub {
-        #region 内部类
+        private static bool _isNotifyProperty = false;
+        /// <summary>
+        /// 启用通知机制从而使展示MessagePath集合的界面响应MessagePath对象状态的变化。
+        /// </summary>
+        public static void SetNotifyProperty() {
+            _isNotifyProperty = true;
+        }
+        private readonly MessagePathSetSet PathSetSet = new MessagePathSetSet();
+        public event Action<IMessagePathId> PathAdded;
+        public event Action<IMessagePathId> PathRemoved;
+
+        public MessagePathHub() {
+        }
+
+        #region IMessageDispatcher Members
+        public IEnumerable<IMessagePathId> GetAllPaths() {
+            foreach (var path in PathSetSet.GetAllMessagePathIds()) {
+                yield return path;
+            }
+        }
+
+        public void Route<TMessage>(TMessage message) where TMessage : IMessage {
+            if (message == null) {
+                throw new ArgumentNullException(nameof(message));
+            }
+            MessagePath<TMessage>[] messagePaths = PathSetSet.GetMessagePathSet<TMessage>().GetMessagePaths();
+            if (messagePaths.Length == 0) {
+                Type messageType = typeof(TMessage);
+                MessageTypeAttribute messageTypeAttr = MessageTypeAttribute.GetMessageTypeAttribute(messageType);
+                if (!messageTypeAttr.IsCanNoPath) {
+                    NTMinerConsole.DevWarn(() => messageType.FullName + "类型的消息没有对应的处理器");
+                }
+            }
+            else {
+                foreach (var messagePath in messagePaths) {
+                    try {
+                        bool canGo = false;
+                        if (message is IEvent evt) {
+                            canGo =
+                                evt.TargetPathId == PathId.Empty // 事件不是特定路径的事件则放行
+                                || messagePath.PathId == PathId.Empty // 路径不是特定事件的路径则放行
+                                || evt.TargetPathId == messagePath.PathId; // 路径是特定事件的路径且路径和事件造型放行
+                        }
+                        else if (message is ICmd cmd) {
+                            // 路径不是特定命令的路径则放行
+                            if (messagePath.PathId == PathId.Empty) {
+                                canGo = true;
+                            }
+                            else {
+                                canGo = messagePath.PathId == cmd.MessageId;
+                            }
+                        }
+                        if (canGo && messagePath.ViaTimesLimit > 0) {
+                            // ViaTimesLimite小于0表示是不限定通过的次数的路径,不限定通过的次数的路径不需要消息每通过一次递减一次ViaTimesLimit计数
+                            messagePath.DecreaseViaTimesLimit(onDownToZero: RemovePath);
+                        }
+                        if (!messagePath.IsEnabled) {
+                            continue;
+                        }
+                        if (canGo) {
+                            switch (messagePath.LogType) {
+                                case LogEnum.DevConsole:
+                                    if (DevMode.IsDevMode) {
+                                        NTMinerConsole.DevDebug(() => $"({typeof(TMessage).Name})->({messagePath.Location.Name}){messagePath.Description}");
+                                    }
+                                    break;
+                                case LogEnum.UserConsole:
+                                    NTMinerConsole.UserInfo($"({typeof(TMessage).Name})->({messagePath.Location.Name}){messagePath.Description}");
+                                    break;
+                                case LogEnum.Log:
+                                    Logger.InfoDebugLine($"({typeof(TMessage).Name})->({messagePath.Location.Name}){messagePath.Description}");
+                                    break;
+                                case LogEnum.None:
+                                default:
+                                    break;
+                            }
+                            messagePath.Go(message);
+                        }
+                    }
+                    catch (Exception e) {
+                        Logger.ErrorDebugLine(e);
+                    }
+                }
+            }
+        }
+
+        public IMessagePathId AddPath<TMessage>(Type location, string description, LogEnum logType, Action<TMessage> action, PathId pathId, int viaTimesLimit = -1) {
+            if (action == null) {
+                throw new ArgumentNullException(nameof(action));
+            }
+            MessagePath<TMessage> path = new MessagePath<TMessage>(location, description, logType, action, pathId, viaTimesLimit);
+            PathSetSet.GetMessagePathSet<TMessage>().AddMessagePath(path);
+            PathAdded?.Invoke(path);
+            return path;
+        }
+
+        public void RemovePath(IMessagePathId pathId) {
+            if (pathId == null) {
+                return;
+            }
+            PathSetSet.RemoveMessagePath(pathId);
+            PathRemoved?.Invoke(pathId);
+        }
+        #endregion
+        #region 私有内部类
         private interface IMessagePathSet {
             Type MessageType { get; }
             IEnumerable<IMessagePathId> GetMessagePaths();
@@ -103,18 +205,12 @@
             }
         }
 
-#if DEBUG
-        public class MessagePath<TMessage> : IMessagePathId, INotifyPropertyChanged {
-#else
-    public class MessagePath<TMessage> : IMessagePathId {
-#endif
+        private class MessagePath<TMessage> : IMessagePathId, INotifyPropertyChanged {
             private readonly Action<TMessage> _path;
             private bool _isEnabled;
             private int _viaTimesLimit;
 
-#if DEBUG
             public event PropertyChangedEventHandler PropertyChanged;
-#endif
 
             internal MessagePath(Type location, string description, LogEnum logType, Action<TMessage> action, PathId pathId, int viaTimesLimit) {
                 if (viaTimesLimit == 0) {
@@ -144,9 +240,9 @@
                 if (newValue == 0) {
                     onDownToZero?.Invoke(this);
                 }
-#if DEBUG
-                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViaTimesLimit)));
-#endif
+                if (_isNotifyProperty) {
+                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViaTimesLimit)));
+                }
             }
 
             public PathId PathId { get; private set; }
@@ -160,9 +256,9 @@
                 get => _isEnabled;
                 set {
                     _isEnabled = value;
-#if DEBUG
-                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEnabled)));
-#endif
+                    if (_isNotifyProperty) {
+                        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEnabled)));
+                    }
                 }
             }
 
@@ -176,103 +272,5 @@
             }
         }
         #endregion
-
-        private readonly MessagePathSetSet PathSetSet = new MessagePathSetSet();
-        public event Action<IMessagePathId> PathAdded;
-        public event Action<IMessagePathId> PathRemoved;
-
-        public MessagePathHub() {
-        }
-
-        #region IMessageDispatcher Members
-        public IEnumerable<IMessagePathId> GetAllPaths() {
-            foreach (var path in PathSetSet.GetAllMessagePathIds()) {
-                yield return path;
-            }
-        }
-
-        public void Route<TMessage>(TMessage message) where TMessage : IMessage {
-            if (message == null) {
-                throw new ArgumentNullException(nameof(message));
-            }
-            MessagePath<TMessage>[] messagePaths = PathSetSet.GetMessagePathSet<TMessage>().GetMessagePaths();
-            if (messagePaths.Length == 0) {
-                Type messageType = typeof(TMessage);
-                MessageTypeAttribute messageTypeAttr = MessageTypeAttribute.GetMessageTypeAttribute(messageType);
-                if (!messageTypeAttr.IsCanNoPath) {
-                    NTMinerConsole.DevWarn(() => messageType.FullName + "类型的消息没有对应的处理器");
-                }
-            }
-            else {
-                foreach (var messagePath in messagePaths) {
-                    try {
-                        bool canGo = false;
-                        if (message is IEvent evt) {
-                            canGo =
-                                evt.TargetPathId == PathId.Empty // 事件不是特定路径的事件则放行
-                                || messagePath.PathId == PathId.Empty // 路径不是特定事件的路径则放行
-                                || evt.TargetPathId == messagePath.PathId; // 路径是特定事件的路径且路径和事件造型放行
-                        }
-                        else if (message is ICmd cmd) {
-                            // 路径不是特定命令的路径则放行
-                            if (messagePath.PathId == PathId.Empty) {
-                                canGo = true;
-                            }
-                            else {
-                                canGo = messagePath.PathId == cmd.MessageId;
-                            }
-                        }
-                        if (canGo && messagePath.ViaTimesLimit > 0) {
-                            // ViaTimesLimite小于0表示是不限定通过的次数的路径,不限定通过的次数的路径不需要消息每通过一次递减一次ViaTimesLimit计数
-                            messagePath.DecreaseViaTimesLimit(onDownToZero: RemovePath);
-                        }
-                        if (!messagePath.IsEnabled) {
-                            continue;
-                        }
-                        if (canGo) {
-                            switch (messagePath.LogType) {
-                                case LogEnum.DevConsole:
-                                    if (DevMode.IsDevMode) {
-                                        NTMinerConsole.DevDebug(() => $"({typeof(TMessage).Name})->({messagePath.Location.Name}){messagePath.Description}");
-                                    }
-                                    break;
-                                case LogEnum.UserConsole:
-                                    NTMinerConsole.UserInfo($"({typeof(TMessage).Name})->({messagePath.Location.Name}){messagePath.Description}");
-                                    break;
-                                case LogEnum.Log:
-                                    Logger.InfoDebugLine($"({typeof(TMessage).Name})->({messagePath.Location.Name}){messagePath.Description}");
-                                    break;
-                                case LogEnum.None:
-                                default:
-                                    break;
-                            }
-                            messagePath.Go(message);
-                        }
-                    }
-                    catch (Exception e) {
-                        Logger.ErrorDebugLine(e);
-                    }
-                }
-            }
-        }
-
-        public IMessagePathId AddPath<TMessage>(Type location, string description, LogEnum logType, Action<TMessage> action, PathId pathId, int viaTimesLimit = -1) {
-            if (action == null) {
-                throw new ArgumentNullException(nameof(action));
-            }
-            MessagePath<TMessage> path = new MessagePath<TMessage>(location, description, logType, action, pathId, viaTimesLimit);
-            PathSetSet.GetMessagePathSet<TMessage>().AddMessagePath(path);
-            PathAdded?.Invoke(path);
-            return path;
-        }
-
-        public void RemovePath(IMessagePathId pathId) {
-            if (pathId == null) {
-                return;
-            }
-            PathSetSet.RemoveMessagePath(pathId);
-            PathRemoved?.Invoke(pathId);
-        }
-        #endregion
     }
 }

+ 27 - 0
src/NTMinerNoDevFee/VirtualRoot.cs

@@ -1,5 +1,6 @@
 using Microsoft.Win32;
 using System;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
@@ -66,6 +67,32 @@ namespace NTMiner {
                         NTMinerRegistry.SetNoDevFeeActiveOn(DateTime.Now);
                         NoDevFee.NoDevFeeUtil.StartAsync();
                     }, typeof(VirtualRoot));
+                BuildEventPath<Per24HourEvent>("周期清理日志文件", LogEnum.None,
+                    path: message => {
+                        #region
+                        try {
+                            List<string> toRemoves = new List<string>();
+                            foreach (var file in Directory.GetFiles(Logger.DirFullPath)) {
+                                FileInfo fileInfo = new FileInfo(file);
+                                if (fileInfo.LastWriteTime.AddDays(2) < DateTime.Now) {
+                                    toRemoves.Add(file);
+                                }
+                            }
+                            if (toRemoves.Count == 0) {
+                                Logger.OkDebugLine("没有过期的Log");
+                            }
+                            else {
+                                foreach (var item in toRemoves) {
+                                    File.Delete(item);
+                                }
+                                Logger.OkDebugLine("过期Log清理完成");
+                            }
+                        }
+                        catch (Exception e) {
+                            Logger.ErrorDebugLine(e);
+                        }
+                        #endregion
+                    }, typeof(VirtualRoot));
                 _waitHandle.WaitOne();
                 Exit();
             }

+ 4 - 16
src/NTMinerlib/TempPath.cs

@@ -5,31 +5,19 @@ namespace NTMiner {
     public static class TempPath {
         public static readonly string TempDirFullName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), NTKeyword.TempDirName);
 
-        private static bool _sIsFirstCallLogsDirFullName = true;
-        public static string LogsDirFullName {
+        private static bool _sIsFirstCallTempLogsDirFullName = true;
+        public static string TempLogsDirFullName {
             get {
                 string dirFullName = Path.Combine(TempDirFullName, NTKeyword.LogsDirName);
-                if (_sIsFirstCallLogsDirFullName) {
+                if (_sIsFirstCallTempLogsDirFullName) {
                     if (!Directory.Exists(dirFullName)) {
                         Directory.CreateDirectory(dirFullName);
                     }
-                    _sIsFirstCallLogsDirFullName = false;
+                    _sIsFirstCallTempLogsDirFullName = false;
                 }
 
                 return dirFullName;
             }
         }
-
-        public static string WebSocketSharpMinerClientLogFileFullName {
-            get {
-                return Path.Combine(LogsDirFullName, NTKeyword.WebSocketSharpMinerClientLogFileName);
-            }
-        }
-
-        public static string WebSocketSharpMinerStudioLogFileFullName {
-            get {
-                return Path.Combine(LogsDirFullName, NTKeyword.WebSocketSharpMinerStudioLogFileName);
-            }
-        }
     }
 }

+ 45 - 25
src/NTMinerlib/VirtualRoot.partials.Common.cs

@@ -11,40 +11,60 @@ namespace NTMiner {
     public static partial class VirtualRoot {
         // 因为多个受保护区域中可能会互相访问,用一把锁可以避免死锁。不用多把锁是因为没有精力去检查每一个受保护区域确保它们不会互相访问导致死锁。
         private static readonly object _locker = new object();
-        public static readonly Process AppProcess = Process.GetCurrentProcess();
-        public static readonly string AppFileFullName = AppProcess.MainModule.FileName;
-        public static readonly string ProcessName = AppProcess.ProcessName;
-        private static PerformanceCounter _performanceCounter = null;
-        private static bool _performanceCounterError = false;
-        private static PerformanceCounter PerformanceCounter {
-            get {
-                if (_performanceCounterError) {
-                    return null;
-                }
-                if (_performanceCounter == null) {
-                    lock (_locker) {
-                        if (_performanceCounter == null) {
-                            try {
-                                // 这是任务管理器看到的内存,不等于AppProcess.WorkingSet64 - AppProcess.PrivateMemorySize64
-                                _performanceCounter = new PerformanceCounter("Process", "Working Set - Private", ProcessName);
-                            }
-                            catch (Exception e) {
-                                _performanceCounterError = true;
-                                Logger.ErrorDebugLine(e);
+        private static readonly Process _appProcess = Process.GetCurrentProcess();
+        public static string AppFileFullName {
+            get { return _appProcess.MainModule.FileName; }
+        }
+
+        // 这是任务管理器看到的内存,不等于AppProcess.WorkingSet64 - AppProcess.PrivateMemorySize64
+        // 因为耗时,所以延迟启动
+        private static PerformanceCounter _memoryCounter;
+        private static PerformanceCounter _threadCounter;
+        private static PerformanceCounter _handleCounter;
+        private static bool _isPerformanceCounterInited = false;
+        private static readonly object _lockForPerformanceCounter = new object();
+        private static void PerformanceCounterInitOnece() {
+            if (!_isPerformanceCounterInited) {
+                lock (_lockForPerformanceCounter) {
+                    if (!_isPerformanceCounterInited) {
+                        string processInstanceName = _appProcess.ProcessName;
+                        PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
+                        // 同一个程序如果运行多次,对应的多个进程名称是通过后缀#1、#2、#3...区分的
+                        string[] instanceNames = cat.GetInstanceNames().Where(a => a.StartsWith(_appProcess.ProcessName)).ToArray();
+                        foreach (string instanceName in instanceNames) {
+                            using (PerformanceCounter cnt = new PerformanceCounter("Process", "ID Process", instanceName, true)) {
+                                int val = (int)cnt.RawValue;
+                                if (val == _appProcess.Id) {
+                                    processInstanceName = instanceName;
+                                    break;
+                                }
                             }
                         }
+                        _memoryCounter = new PerformanceCounter("Process", "Working Set - Private", processInstanceName, readOnly: true);
+                        _threadCounter = new PerformanceCounter("Process", "Thread Count", processInstanceName, readOnly: true);
+                        _handleCounter = new PerformanceCounter("Process", "Handle Count", processInstanceName, readOnly: true);
+                        _isPerformanceCounterInited = true;
                     }
                 }
-                return _performanceCounter;
             }
         }
 
         public static double ProcessMemoryMb {
             get {
-                if (PerformanceCounter == null) {
-                    return 0.0;
-                }
-                return PerformanceCounter.RawValue / NTKeyword.DoubleM;
+                PerformanceCounterInitOnece();
+                return _memoryCounter.RawValue / NTKeyword.DoubleM;
+            }
+        }
+        public static long ThreadCount {
+            get {
+                PerformanceCounterInitOnece();
+                return _threadCounter.RawValue;
+            }
+        }
+        public static long HandleCount {
+            get {
+                PerformanceCounterInitOnece();
+                return _handleCounter.RawValue;
             }
         }
 

+ 1 - 1
src/NTMinerlib/Windows/Cpu.cs

@@ -38,7 +38,7 @@ namespace NTMiner.Windows {
                     lock (_locker) {
                         if (_cpuCounterTotal == null) {
                             try {
-                                _cpuCounterTotal = new PerformanceCounter("Processor", "% Processor Time", "_Total");
+                                _cpuCounterTotal = new PerformanceCounter("Processor", "% Processor Time", "_Total", readOnly: true);
                             }
                             catch (Exception e) {
                                 _cpuCounterTotalError = true;

BIN
src/ThirdPartyDlls/websocket-sharp.dll


+ 0 - 11730
src/ThirdPartyDlls/websocket-sharp.xml

@@ -1,11730 +0,0 @@
-<?xml version="1.0"?>
-<doc>
-    <assembly>
-        <name>websocket-sharp</name>
-    </assembly>
-    <members>
-        <member name="T:WebSocketSharp.Ext">
-            <summary>
-            Provides a set of static methods for websocket-sharp.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Contains(System.String,System.Char[])">
-            <summary>
-            Determines whether the specified string contains any of characters in
-            the specified array of <see cref="T:System.Char"/>.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="value"/> contains any of characters in
-            <paramref name="anyOf"/>; otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            A <see cref="T:System.String"/> to test.
-            </param>
-            <param name="anyOf">
-            An array of <see cref="T:System.Char"/> that contains one or more characters to
-            seek.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.EqualsWith(System.Int32,System.Char,System.Action{System.Int32})">
-            <summary>
-            Determines whether the specified <see cref="T:System.Int32"/> equals the specified <see cref="T:System.Char"/>,
-            and invokes the specified <c>Action&lt;int&gt;</c> delegate at the same time.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="value"/> equals <paramref name="c"/>;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            An <see cref="T:System.Int32"/> to compare.
-            </param>
-            <param name="c">
-            A <see cref="T:System.Char"/> to compare.
-            </param>
-            <param name="action">
-            An <c>Action&lt;int&gt;</c> delegate that references the method(s) called
-            at the same time as comparing. An <see cref="T:System.Int32"/> parameter to pass to
-            the method(s) is <paramref name="value"/>.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.GetAbsolutePath(System.Uri)">
-            <summary>
-            Gets the absolute path from the specified <see cref="T:System.Uri"/>.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that represents the absolute path if it's successfully found;
-            otherwise, <see langword="null"/>.
-            </returns>
-            <param name="uri">
-            A <see cref="T:System.Uri"/> that represents the URI to get the absolute path from.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.GetName(System.String,System.Char)">
-            <summary>
-            Gets the name from the specified string that contains a pair of
-            name and value separated by a character.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.String"/> that represents the name.
-              </para>
-              <para>
-              <see langword="null"/> if the name is not present.
-              </para>
-            </returns>
-            <param name="nameAndValue">
-            A <see cref="T:System.String"/> that contains a pair of name and value.
-            </param>
-            <param name="separator">
-            A <see cref="T:System.Char"/> used to separate name and value.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.GetValue(System.String,System.Char)">
-            <summary>
-            Gets the value from the specified string that contains a pair of
-            name and value separated by a character.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.String"/> that represents the value.
-              </para>
-              <para>
-              <see langword="null"/> if the value is not present.
-              </para>
-            </returns>
-            <param name="nameAndValue">
-            A <see cref="T:System.String"/> that contains a pair of name and value.
-            </param>
-            <param name="separator">
-            A <see cref="T:System.Char"/> used to separate name and value.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.GetValue(System.String,System.Char,System.Boolean)">
-            <summary>
-            Gets the value from the specified string that contains a pair of
-            name and value separated by a character.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.String"/> that represents the value.
-              </para>
-              <para>
-              <see langword="null"/> if the value is not present.
-              </para>
-            </returns>
-            <param name="nameAndValue">
-            A <see cref="T:System.String"/> that contains a pair of name and value.
-            </param>
-            <param name="separator">
-            A <see cref="T:System.Char"/> used to separate name and value.
-            </param>
-            <param name="unquote">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if unquotes the value; otherwise,
-            <c>false</c>.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.TryCreateWebSocketUri(System.String,System.Uri@,System.String@)">
-            <summary>
-            Tries to create a new <see cref="T:System.Uri"/> for WebSocket with
-            the specified <paramref name="uriString"/>.
-            </summary>
-            <returns>
-            <c>true</c> if the <see cref="T:System.Uri"/> was successfully created;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="uriString">
-            A <see cref="T:System.String"/> that represents a WebSocket URL to try.
-            </param>
-            <param name="result">
-            When this method returns, a <see cref="T:System.Uri"/> that
-            represents the WebSocket URL or <see langword="null"/>
-            if <paramref name="uriString"/> is invalid.
-            </param>
-            <param name="message">
-            When this method returns, a <see cref="T:System.String"/> that
-            represents an error message or <see langword="null"/>
-            if <paramref name="uriString"/> is valid.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.GetDescription(WebSocketSharp.Net.HttpStatusCode)">
-            <summary>
-            Gets the description of the specified HTTP status code.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that represents the description of
-            the HTTP status code.
-            </returns>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpStatusCode"/> enum values.
-              </para>
-              <para>
-              It specifies the HTTP status code.
-              </para>
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.GetStatusDescription(System.Int32)">
-            <summary>
-            Gets the description of the specified HTTP status code.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.String"/> that represents the description of
-              the HTTP status code.
-              </para>
-              <para>
-              An empty string if the description is not present.
-              </para>
-            </returns>
-            <param name="code">
-            An <see cref="T:System.Int32"/> that specifies the HTTP status code.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.IsCloseStatusCode(System.UInt16)">
-            <summary>
-            Determines whether the specified ushort is in the range of
-            the status code for the WebSocket connection close.
-            </summary>
-            <remarks>
-              <para>
-              The ranges are the following:
-              </para>
-              <list type="bullet">
-                <item>
-                  <term>
-                  1000-2999: These numbers are reserved for definition by
-                  the WebSocket protocol.
-                  </term>
-                </item>
-                <item>
-                  <term>
-                  3000-3999: These numbers are reserved for use by libraries,
-                  frameworks, and applications.
-                  </term>
-                </item>
-                <item>
-                  <term>
-                  4000-4999: These numbers are reserved for private use.
-                  </term>
-                </item>
-              </list>
-            </remarks>
-            <returns>
-            <c>true</c> if <paramref name="value"/> is in the range of
-            the status code for the close; otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            A <see cref="T:System.UInt16"/> to test.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.IsEnclosedIn(System.String,System.Char)">
-            <summary>
-            Determines whether the specified string is enclosed in
-            the specified character.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="value"/> is enclosed in
-            <paramref name="c"/>; otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            A <see cref="T:System.String"/> to test.
-            </param>
-            <param name="c">
-            A <see cref="T:System.Char"/> to find.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.IsHostOrder(WebSocketSharp.ByteOrder)">
-            <summary>
-            Determines whether the specified byte order is host (this computer
-            architecture) byte order.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="order"/> is host byte order; otherwise,
-            <c>false</c>.
-            </returns>
-            <param name="order">
-            One of the <see cref="T:WebSocketSharp.ByteOrder"/> enum values to test.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.IsLocal(System.Net.IPAddress)">
-            <summary>
-            Determines whether the specified IP address is a local IP address.
-            </summary>
-            <remarks>
-            This local means NOT REMOTE for the current host.
-            </remarks>
-            <returns>
-            <c>true</c> if <paramref name="address"/> is a local IP address;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="address">
-            A <see cref="T:System.Net.IPAddress"/> to test.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="address"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Ext.IsNullOrEmpty(System.String)">
-            <summary>
-            Determines whether the specified string is <see langword="null"/> or
-            an empty string.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="value"/> is <see langword="null"/> or
-            an empty string; otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            A <see cref="T:System.String"/> to test.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.IsPredefinedScheme(System.String)">
-            <summary>
-            Determines whether the specified string is a predefined scheme.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="value"/> is a predefined scheme;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            A <see cref="T:System.String"/> to test.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.MaybeUri(System.String)">
-            <summary>
-            Determines whether the specified string is a URI string.
-            </summary>
-            <returns>
-            <c>true</c> if <paramref name="value"/> may be a URI string;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="value">
-            A <see cref="T:System.String"/> to test.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.SubArray``1(``0[],System.Int32,System.Int32)">
-            <summary>
-            Retrieves a sub-array from the specified array. A sub-array starts at
-            the specified index in the array.
-            </summary>
-            <returns>
-            An array of T that receives a sub-array.
-            </returns>
-            <param name="array">
-            An array of T from which to retrieve a sub-array.
-            </param>
-            <param name="startIndex">
-            An <see cref="T:System.Int32"/> that represents the zero-based index in the array
-            at which retrieving starts.
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that represents the number of elements to retrieve.
-            </param>
-            <typeparam name="T">
-            The type of elements in the array.
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="array"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="startIndex"/> is less than zero.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="startIndex"/> is greater than the end of the array.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than zero.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is greater than the number of elements from
-              <paramref name="startIndex"/> to the end of the array.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Ext.SubArray``1(``0[],System.Int64,System.Int64)">
-            <summary>
-            Retrieves a sub-array from the specified array. A sub-array starts at
-            the specified index in the array.
-            </summary>
-            <returns>
-            An array of T that receives a sub-array.
-            </returns>
-            <param name="array">
-            An array of T from which to retrieve a sub-array.
-            </param>
-            <param name="startIndex">
-            A <see cref="T:System.Int64"/> that represents the zero-based index in the array
-            at which retrieving starts.
-            </param>
-            <param name="length">
-            A <see cref="T:System.Int64"/> that represents the number of elements to retrieve.
-            </param>
-            <typeparam name="T">
-            The type of elements in the array.
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="array"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="startIndex"/> is less than zero.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="startIndex"/> is greater than the end of the array.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than zero.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is greater than the number of elements from
-              <paramref name="startIndex"/> to the end of the array.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.Int32,System.Action)">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            An <see cref="T:System.Int32"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-            An <see cref="T:System.Action"/> delegate to execute.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.Int64,System.Action)">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            A <see cref="T:System.Int64"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-            An <see cref="T:System.Action"/> delegate to execute.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.UInt32,System.Action)">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            A <see cref="T:System.UInt32"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-            An <see cref="T:System.Action"/> delegate to execute.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.UInt64,System.Action)">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            A <see cref="T:System.UInt64"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-            An <see cref="T:System.Action"/> delegate to execute.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.Int32,System.Action{System.Int32})">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            An <see cref="T:System.Int32"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-              <para>
-              An <c>Action&lt;int&gt;</c> delegate to execute.
-              </para>
-              <para>
-              The <see cref="T:System.Int32"/> parameter is the zero-based count of iteration.
-              </para>
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.Int64,System.Action{System.Int64})">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            A <see cref="T:System.Int64"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-              <para>
-              An <c>Action&lt;long&gt;</c> delegate to execute.
-              </para>
-              <para>
-              The <see cref="T:System.Int64"/> parameter is the zero-based count of iteration.
-              </para>
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.UInt32,System.Action{System.UInt32})">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            A <see cref="T:System.UInt32"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-              <para>
-              An <c>Action&lt;uint&gt;</c> delegate to execute.
-              </para>
-              <para>
-              The <see cref="T:System.UInt32"/> parameter is the zero-based count of iteration.
-              </para>
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.Times(System.UInt64,System.Action{System.UInt64})">
-            <summary>
-            Executes the specified delegate <paramref name="n"/> times.
-            </summary>
-            <param name="n">
-            A <see cref="T:System.UInt64"/> that specifies the number of times to execute.
-            </param>
-            <param name="action">
-              <para>
-              An <c>Action&lt;ulong&gt;</c> delegate to execute.
-              </para>
-              <para>
-              The <see cref="T:System.UInt64"/> parameter is the zero-based count of iteration.
-              </para>
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.To``1(System.Byte[],WebSocketSharp.ByteOrder)">
-            <summary>
-            Converts the specified byte array to the specified type value.
-            </summary>
-            <returns>
-              <para>
-              A T converted from <paramref name="source"/>.
-              </para>
-              <para>
-              The default value of T if not converted.
-              </para>
-            </returns>
-            <param name="source">
-            An array of <see cref="T:System.Byte"/> to convert.
-            </param>
-            <param name="sourceOrder">
-              <para>
-              One of the <see cref="T:WebSocketSharp.ByteOrder"/> enum values.
-              </para>
-              <para>
-              It specifies the byte order of <paramref name="source"/>.
-              </para>
-            </param>
-            <typeparam name="T">
-              <para>
-              The type of the return.
-              </para>
-              <para>
-              <see cref="T:System.Boolean"/>, <see cref="T:System.Char"/>, <see cref="T:System.Double"/>,
-              <see cref="T:System.Single"/>, <see cref="T:System.Int32"/>, <see cref="T:System.Int64"/>,
-              <see cref="T:System.Int16"/>, <see cref="T:System.UInt32"/>, <see cref="T:System.UInt64"/>,
-              or <see cref="T:System.UInt16"/>.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="source"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Ext.ToByteArray``1(``0,WebSocketSharp.ByteOrder)">
-            <summary>
-            Converts the specified value to a byte array.
-            </summary>
-            <returns>
-            An array of <see cref="T:System.Byte"/> converted from <paramref name="value"/>.
-            </returns>
-            <param name="value">
-            A T to convert.
-            </param>
-            <param name="order">
-              <para>
-              One of the <see cref="T:WebSocketSharp.ByteOrder"/> enum values.
-              </para>
-              <para>
-              It specifies the byte order of the return.
-              </para>
-            </param>
-            <typeparam name="T">
-              <para>
-              The type of <paramref name="value"/>.
-              </para>
-              <para>
-              <see cref="T:System.Boolean"/>, <see cref="T:System.Byte"/>, <see cref="T:System.Char"/>,
-              <see cref="T:System.Double"/>, <see cref="T:System.Single"/>, <see cref="T:System.Int32"/>,
-              <see cref="T:System.Int64"/>, <see cref="T:System.Int16"/>, <see cref="T:System.UInt32"/>,
-              <see cref="T:System.UInt64"/>, or <see cref="T:System.UInt16"/>.
-              </para>
-            </typeparam>
-        </member>
-        <member name="M:WebSocketSharp.Ext.ToHostOrder(System.Byte[],WebSocketSharp.ByteOrder)">
-            <summary>
-            Converts the order of elements in the specified byte array to
-            host (this computer architecture) byte order.
-            </summary>
-            <returns>
-              <para>
-              An array of <see cref="T:System.Byte"/> converted from
-              <paramref name="source"/>.
-              </para>
-              <para>
-              <paramref name="source"/> if the number of elements in
-              it is less than 2 or <paramref name="sourceOrder"/> is
-              same as host byte order.
-              </para>
-            </returns>
-            <param name="source">
-            An array of <see cref="T:System.Byte"/> to convert.
-            </param>
-            <param name="sourceOrder">
-              <para>
-              One of the <see cref="T:WebSocketSharp.ByteOrder"/> enum values.
-              </para>
-              <para>
-              It specifies the order of elements in <paramref name="source"/>.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="source"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Ext.ToString``1(``0[],System.String)">
-            <summary>
-            Converts the specified array to a string.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.String"/> converted by concatenating each element of
-              <paramref name="array"/> across <paramref name="separator"/>.
-              </para>
-              <para>
-              An empty string if <paramref name="array"/> is an empty array.
-              </para>
-            </returns>
-            <param name="array">
-            An array of T to convert.
-            </param>
-            <param name="separator">
-            A <see cref="T:System.String"/> used to separate each element of
-            <paramref name="array"/>.
-            </param>
-            <typeparam name="T">
-            The type of elements in <paramref name="array"/>.
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="array"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Ext.ToUri(System.String)">
-            <summary>
-            Converts the specified string to a <see cref="T:System.Uri"/>.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.Uri"/> converted from <paramref name="value"/>.
-              </para>
-              <para>
-              <see langword="null"/> if the conversion has failed.
-              </para>
-            </returns>
-            <param name="value">
-            A <see cref="T:System.String"/> to convert.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Ext.WriteContent(WebSocketSharp.Net.HttpListenerResponse,System.Byte[])">
-            <summary>
-            Sends the specified content data with the HTTP response.
-            </summary>
-            <param name="response">
-            A <see cref="T:WebSocketSharp.Net.HttpListenerResponse"/> that represents the HTTP response
-            used to send the content data.
-            </param>
-            <param name="content">
-            An array of <see cref="T:System.Byte"/> that specifies the content data to send.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="response"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="content"/> is <see langword="null"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.MessageEventArgs">
-            <summary>
-            Represents the event data for the <see cref="E:WebSocketSharp.WebSocket.OnMessage"/> event.
-            </summary>
-            <remarks>
-              <para>
-              That event occurs when the <see cref="T:WebSocketSharp.WebSocket"/> receives
-              a message or a ping if the <see cref="P:WebSocketSharp.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="P:WebSocketSharp.MessageEventArgs.Data"/> or <see cref="P:WebSocketSharp.MessageEventArgs.RawData"/> property.
-              </para>
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.MessageEventArgs.Opcode">
-            <summary>
-            Gets the opcode for the message.
-            </summary>
-            <value>
-            <see cref="F:WebSocketSharp.Opcode.Text"/>, <see cref="F:WebSocketSharp.Opcode.Binary"/>,
-            or <see cref="F:WebSocketSharp.Opcode.Ping"/>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.MessageEventArgs.Data">
-            <summary>
-            Gets the message data as a <see cref="T:System.String"/>.
-            </summary>
-            <value>
-            A <see cref="T:System.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>
-        </member>
-        <member name="P:WebSocketSharp.MessageEventArgs.IsBinary">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.MessageEventArgs.IsPing">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.MessageEventArgs.IsText">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.MessageEventArgs.RawData">
-            <summary>
-            Gets the message data as an array of <see cref="T:System.Byte"/>.
-            </summary>
-            <value>
-            An array of <see cref="T:System.Byte"/> that represents the message data.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.CloseEventArgs">
-            <summary>
-            Represents the event data for the <see cref="E:WebSocketSharp.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="P:WebSocketSharp.CloseEventArgs.Code"/> or <see cref="P:WebSocketSharp.CloseEventArgs.Reason"/> property.
-              </para>
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.CloseEventArgs.Code">
-            <summary>
-            Gets the status code for the connection close.
-            </summary>
-            <value>
-            A <see cref="T:System.UInt16"/> that represents the status code for
-            the connection close if present.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.CloseEventArgs.Reason">
-            <summary>
-            Gets the reason for the connection close.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the reason for
-            the connection close if present.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.CloseEventArgs.WasClean">
-            <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>
-        </member>
-        <member name="T:WebSocketSharp.ByteOrder">
-            <summary>
-            Specifies the byte order.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.ByteOrder.Little">
-            <summary>
-            Specifies Little-endian.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.ByteOrder.Big">
-            <summary>
-            Specifies Big-endian.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.ErrorEventArgs">
-            <summary>
-            Represents the event data for the <see cref="E:WebSocketSharp.WebSocket.OnError"/> event.
-            </summary>
-            <remarks>
-              <para>
-              That event occurs when the <see cref="T:WebSocketSharp.WebSocket"/> gets an error.
-              </para>
-              <para>
-              If you would like to get the error message, you should access
-              the <see cref="P:WebSocketSharp.ErrorEventArgs.Message"/> property.
-              </para>
-              <para>
-              And if the error is due to an exception, you can get it by accessing
-              the <see cref="P:WebSocketSharp.ErrorEventArgs.Exception"/> property.
-              </para>
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.ErrorEventArgs.Exception">
-            <summary>
-            Gets the exception that caused the error.
-            </summary>
-            <value>
-            An <see cref="T:System.Exception"/> instance that represents the cause of
-            the error if it is due to an exception; otherwise, <see langword="null"/>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.ErrorEventArgs.Message">
-            <summary>
-            Gets the error message.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the error message.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.WebSocket">
-            <summary>
-            Implements the WebSocket interface.
-            </summary>
-            <remarks>
-              <para>
-              This class provides a set of methods and properties for two-way
-              communication using the WebSocket protocol.
-              </para>
-              <para>
-              The WebSocket protocol is defined in
-              <see href="http://tools.ietf.org/html/rfc6455">RFC 6455</see>.
-              </para>
-            </remarks>
-        </member>
-        <member name="F:WebSocketSharp.WebSocket.EmptyBytes">
-            <summary>
-            Represents the empty array of <see cref="T:System.Byte"/> used internally.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.WebSocket.FragmentLength">
-            <summary>
-            Represents the length used to determine whether the data should be fragmented in sending.
-            </summary>
-            <remarks>
-              <para>
-              The data will be fragmented if that length is greater than the value of this field.
-              </para>
-              <para>
-              If you would like to change the value, you must set it to a value between <c>125</c> and
-              <c>Int32.MaxValue - 14</c> inclusive.
-              </para>
-            </remarks>
-        </member>
-        <member name="F:WebSocketSharp.WebSocket.RandomNumber">
-            <summary>
-            Represents the random number generator used internally.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.#ctor(System.String,System.String[])">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.WebSocket"/> class with
-            <paramref name="url"/> and optionally <paramref name="protocols"/>.
-            </summary>
-            <param name="url">
-              <para>
-              A <see cref="T:System.String"/> that specifies the URL to which to connect.
-              </para>
-              <para>
-              The scheme of the URL must be ws or wss.
-              </para>
-              <para>
-              The new instance uses a secure connection if the scheme is wss.
-              </para>
-            </param>
-            <param name="protocols">
-              <para>
-              An array of <see cref="T:System.String"/> that specifies the names of
-              the subprotocols if necessary.
-              </para>
-              <para>
-              Each value of the array must be a token defined in
-              <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
-              RFC 2616</see>.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="url"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="url"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="url"/> is an invalid WebSocket URL string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="protocols"/> contains a value that is not a token.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="protocols"/> contains a value twice.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Compression">
-            <summary>
-            Gets or sets the compression method used to compress a message.
-            </summary>
-            <remarks>
-            The set operation does nothing if the connection has already been
-            established or it is closing.
-            </remarks>
-            <value>
-              <para>
-              One of the <see cref="T:WebSocketSharp.CompressionMethod"/> enum values.
-              </para>
-              <para>
-              It specifies the compression method used to compress a message.
-              </para>
-              <para>
-              The default value is <see cref="F:WebSocketSharp.CompressionMethod.None"/>.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The set operation is not available if this instance is not a client.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Cookies">
-            <summary>
-            Gets the HTTP cookies included in the handshake request/response.
-            </summary>
-            <value>
-              <para>
-              An <see cref="T:System.Collections.Generic.IEnumerable{WebSocketSharp.Net.Cookie}"/>
-              instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the cookies.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Credentials">
-            <summary>
-            Gets the credentials for the HTTP authentication (Basic/Digest).
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Net.NetworkCredential"/> that represents the credentials
-              used to authenticate the client.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.EmitOnPing">
-            <summary>
-            Gets or sets a value indicating whether a <see cref="E:WebSocketSharp.WebSocket.OnMessage"/> event
-            is emitted when a ping is received.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if this instance emits a <see cref="E:WebSocketSharp.WebSocket.OnMessage"/> event
-              when receives a ping; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.EnableRedirection">
-            <summary>
-            Gets or sets a value indicating whether the URL redirection for
-            the handshake request is allowed.
-            </summary>
-            <remarks>
-            The set operation does nothing if the connection has already been
-            established or it is closing.
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if this instance allows the URL redirection for
-              the handshake request; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The set operation is not available if this instance is not a client.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Extensions">
-            <summary>
-            Gets the extensions selected by server.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that will be a list of the extensions
-            negotiated between client and server, or an empty string if
-            not specified or selected.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.IsAlive">
-            <summary>
-            Gets a value indicating whether the connection is alive.
-            </summary>
-            <remarks>
-            The get operation returns the value by using a ping/pong
-            if the current state of the connection is Open.
-            </remarks>
-            <value>
-            <c>true</c> if the connection is alive; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.IsSecure">
-            <summary>
-            Gets a value indicating whether a secure connection is used.
-            </summary>
-            <value>
-            <c>true</c> if this instance uses a secure connection; otherwise,
-            <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Log">
-            <summary>
-            Gets the logging function.
-            </summary>
-            <remarks>
-            The default logging level is <see cref="F:WebSocketSharp.LogLevel.Error"/>.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Logger"/> that provides the logging function.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Origin">
-            <summary>
-            Gets or sets the value of the HTTP Origin header to send with
-            the handshake request.
-            </summary>
-            <remarks>
-              <para>
-              The HTTP Origin header is defined in
-              <see href="http://tools.ietf.org/html/rfc6454#section-7">
-              Section 7 of RFC 6454</see>.
-              </para>
-              <para>
-              This instance sends the Origin header if this property has any.
-              </para>
-              <para>
-              The set operation does nothing if the connection has already been
-              established or it is closing.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of the Origin
-              header to send.
-              </para>
-              <para>
-              The syntax is &lt;scheme&gt;://&lt;host&gt;[:&lt;port&gt;].
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The set operation is not available if this instance is not a client.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The value specified for a set operation is not an absolute URI string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value specified for a set operation includes the path segments.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Protocol">
-            <summary>
-            Gets the name of subprotocol selected by the server.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that will be one of the names of
-              subprotocols specified by client.
-              </para>
-              <para>
-              An empty string if not specified or selected.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.ReadyState">
-            <summary>
-            Gets the current state of the connection.
-            </summary>
-            <value>
-              <para>
-              One of the <see cref="T:WebSocketSharp.WebSocketState"/> enum values.
-              </para>
-              <para>
-              It indicates the current state of the connection.
-              </para>
-              <para>
-              The default value is <see cref="F:WebSocketSharp.WebSocketState.Connecting"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.SslConfiguration">
-            <summary>
-            Gets the configuration for secure connection.
-            </summary>
-            <remarks>
-            This configuration will be referenced when attempts to connect,
-            so it must be configured before any connect method is called.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.ClientSslConfiguration"/> that represents
-            the configuration used to establish a secure connection.
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              This instance is not a client.
-              </para>
-              <para>
-              This instance does not use a secure connection.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.Url">
-            <summary>
-            Gets the URL to which to connect.
-            </summary>
-            <value>
-            A <see cref="T:System.Uri"/> that represents the URL to which to connect.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.WebSocket.WaitTime">
-            <summary>
-            Gets or sets the time to wait for the response to the ping or close.
-            </summary>
-            <remarks>
-            The set operation does nothing if the connection has already been
-            established or it is closing.
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.TimeSpan"/> to wait for the response.
-              </para>
-              <para>
-              The default value is the same as 5 seconds if this instance is
-              a client.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is zero or less.
-            </exception>
-        </member>
-        <member name="E:WebSocketSharp.WebSocket.OnClose">
-            <summary>
-            Occurs when the WebSocket connection has been closed.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.WebSocket.OnError">
-            <summary>
-            Occurs when the <see cref="T:WebSocketSharp.WebSocket"/> gets an error.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.WebSocket.OnMessage">
-            <summary>
-            Occurs when the <see cref="T:WebSocketSharp.WebSocket"/> receives a message.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.WebSocket.OnOpen">
-            <summary>
-            Occurs when the WebSocket connection has been established.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Accept">
-            <summary>
-            Accepts the handshake request.
-            </summary>
-            <remarks>
-            This method does nothing if the handshake request has already been
-            accepted.
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              This instance is a client.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The close process is in progress.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The connection has already been closed.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.AcceptAsync">
-            <summary>
-            Accepts the handshake request asynchronously.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the accept process to be complete.
-              </para>
-              <para>
-              This method does nothing if the handshake request has already been
-              accepted.
-              </para>
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              This instance is a client.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The close process is in progress.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The connection has already been closed.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Close">
-            <summary>
-            Closes the connection.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Close(System.UInt16)">
-            <summary>
-            Closes the connection with the specified code.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="code"/> is less than 1000 or greater than 4999.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1011 (server error).
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              It cannot be used by servers.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Close(WebSocketSharp.CloseStatusCode)">
-            <summary>
-            Closes the connection with the specified code.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.ServerError"/>.
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              It cannot be used by servers.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Close(System.UInt16,System.String)">
-            <summary>
-            Closes the connection with the specified code and reason.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1011 (server error).
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              It cannot be used by servers.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Close(WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Closes the connection with the specified code and reason.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.ServerError"/>.
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              It cannot be used by servers.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.CloseAsync">
-            <summary>
-            Closes the connection asynchronously.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.CloseAsync(System.UInt16)">
-            <summary>
-            Closes the connection asynchronously with the specified code.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="code"/> is less than 1000 or greater than 4999.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1011 (server error).
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              It cannot be used by servers.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.CloseAsync(WebSocketSharp.CloseStatusCode)">
-            <summary>
-            Closes the connection asynchronously with the specified code.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.ServerError"/>.
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              It cannot be used by servers.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.CloseAsync(System.UInt16,System.String)">
-            <summary>
-            Closes the connection asynchronously with the specified code and reason.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1011 (server error).
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              It cannot be used by servers.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.CloseAsync(WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Closes the connection asynchronously with the specified code and reason.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.ServerError"/>.
-              It cannot be used by clients.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              It cannot be used by servers.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Connect">
-            <summary>
-            Establishes a connection.
-            </summary>
-            <remarks>
-            This method does nothing if the connection has already been established.
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              This instance is not a client.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The close process is in progress.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              A series of reconnecting has failed.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.ConnectAsync">
-            <summary>
-            Establishes a connection asynchronously.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the connect process to be complete.
-              </para>
-              <para>
-              This method does nothing if the connection has already been
-              established.
-              </para>
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              This instance is not a client.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The close process is in progress.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              A series of reconnecting has failed.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Ping">
-            <summary>
-            Sends a ping using the WebSocket connection.
-            </summary>
-            <returns>
-            <c>true</c> if the send has done with no error and a pong has been
-            received within a time; otherwise, <c>false</c>.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Ping(System.String)">
-            <summary>
-            Sends a ping with <paramref name="message"/> using the WebSocket
-            connection.
-            </summary>
-            <returns>
-            <c>true</c> if the send has done with no error and a pong has been
-            received within a time; otherwise, <c>false</c>.
-            </returns>
-            <param name="message">
-              <para>
-              A <see cref="T:System.String"/> that represents the message to send.
-              </para>
-              <para>
-              The size must be 125 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="message"/> could not be UTF-8-encoded.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="message"/> is greater than 125 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Send(System.Byte[])">
-            <summary>
-            Sends the specified data using the WebSocket connection.
-            </summary>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Send(System.IO.FileInfo)">
-            <summary>
-            Sends the specified file using the WebSocket connection.
-            </summary>
-            <param name="fileInfo">
-              <para>
-              A <see cref="T:System.IO.FileInfo"/> that specifies the file to send.
-              </para>
-              <para>
-              The file is sent as the binary data.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="fileInfo"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The file does not exist.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The file could not be opened.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Send(System.String)">
-            <summary>
-            Sends the specified data using the WebSocket connection.
-            </summary>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.Send(System.IO.Stream,System.Int32)">
-            <summary>
-            Sends the data from the specified stream using the WebSocket connection.
-            </summary>
-            <param name="stream">
-              <para>
-              A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-              </para>
-              <para>
-              The data is sent as the binary data.
-              </para>
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SendAsync(System.Byte[],System.Action{System.Boolean})">
-            <summary>
-            Sends the specified data asynchronously using the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SendAsync(System.IO.FileInfo,System.Action{System.Boolean})">
-            <summary>
-            Sends the specified file asynchronously using the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="fileInfo">
-              <para>
-              A <see cref="T:System.IO.FileInfo"/> that specifies the file to send.
-              </para>
-              <para>
-              The file is sent as the binary data.
-              </para>
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="fileInfo"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The file does not exist.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The file could not be opened.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SendAsync(System.String,System.Action{System.Boolean})">
-            <summary>
-            Sends the specified data asynchronously using the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SendAsync(System.IO.Stream,System.Int32,System.Action{System.Boolean})">
-            <summary>
-            Sends the data from the specified stream asynchronously using
-            the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="stream">
-              <para>
-              A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-              </para>
-              <para>
-              The data is sent as the binary data.
-              </para>
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SetCookie(WebSocketSharp.Net.Cookie)">
-            <summary>
-            Sets an HTTP cookie to send with the handshake request.
-            </summary>
-            <remarks>
-            This method does nothing if the connection has already been
-            established or it is closing.
-            </remarks>
-            <param name="cookie">
-            A <see cref="T:WebSocketSharp.Net.Cookie"/> that represents the cookie to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            This instance is not a client.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookie"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SetCredentials(System.String,System.String,System.Boolean)">
-            <summary>
-            Sets the credentials for the HTTP authentication (Basic/Digest).
-            </summary>
-            <remarks>
-            This method does nothing if the connection has already been
-            established or it is closing.
-            </remarks>
-            <param name="username">
-              <para>
-              A <see cref="T:System.String"/> that represents the username associated with
-              the credentials.
-              </para>
-              <para>
-              <see langword="null"/> or an empty string if initializes
-              the credentials.
-              </para>
-            </param>
-            <param name="password">
-              <para>
-              A <see cref="T:System.String"/> that represents the password for the username
-              associated with the credentials.
-              </para>
-              <para>
-              <see langword="null"/> or an empty string if not necessary.
-              </para>
-            </param>
-            <param name="preAuth">
-            <c>true</c> if sends the credentials for the Basic authentication in
-            advance with the first handshake request; otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            This instance is not a client.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="username"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="password"/> contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.SetProxy(System.String,System.String,System.String)">
-            <summary>
-            Sets the URL of the HTTP proxy server through which to connect and
-            the credentials for the HTTP proxy authentication (Basic/Digest).
-            </summary>
-            <remarks>
-            This method does nothing if the connection has already been
-            established or it is closing.
-            </remarks>
-            <param name="url">
-              <para>
-              A <see cref="T:System.String"/> that represents the URL of the proxy server
-              through which to connect.
-              </para>
-              <para>
-              The syntax is http://&lt;host&gt;[:&lt;port&gt;].
-              </para>
-              <para>
-              <see langword="null"/> or an empty string if initializes the URL and
-              the credentials.
-              </para>
-            </param>
-            <param name="username">
-              <para>
-              A <see cref="T:System.String"/> that represents the username associated with
-              the credentials.
-              </para>
-              <para>
-              <see langword="null"/> or an empty string if the credentials are not
-              necessary.
-              </para>
-            </param>
-            <param name="password">
-              <para>
-              A <see cref="T:System.String"/> that represents the password for the username
-              associated with the credentials.
-              </para>
-              <para>
-              <see langword="null"/> or an empty string if not necessary.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            This instance is not a client.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="url"/> is not an absolute URI string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The scheme of <paramref name="url"/> is not http.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="url"/> includes the path segments.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="username"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="password"/> contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.WebSocket.System#IDisposable#Dispose">
-            <summary>
-            Closes the connection and releases all associated resources.
-            </summary>
-            <remarks>
-              <para>
-              This method closes the connection with close status 1001 (going away).
-              </para>
-              <para>
-              And this method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-        </member>
-        <member name="T:WebSocketSharp.Server.WebSocketServer">
-            <summary>
-            Provides a WebSocket protocol server.
-            </summary>
-            <remarks>
-            This class can provide multiple WebSocket services.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> class.
-            </summary>
-            <remarks>
-            The new instance listens for incoming handshake requests on
-            <see cref="F:System.Net.IPAddress.Any"/> and port 80.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.#ctor(System.Int32)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> class
-            with the specified <paramref name="port"/>.
-            </summary>
-            <remarks>
-              <para>
-              The new instance listens for incoming handshake requests on
-              <see cref="F:System.Net.IPAddress.Any"/> and <paramref name="port"/>.
-              </para>
-              <para>
-              It provides secure connections if <paramref name="port"/> is 443.
-              </para>
-            </remarks>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.#ctor(System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> class
-            with the specified <paramref name="url"/>.
-            </summary>
-            <remarks>
-              <para>
-              The new instance listens for incoming handshake requests on
-              the IP address of the host of <paramref name="url"/> and
-              the port of <paramref name="url"/>.
-              </para>
-              <para>
-              Either port 80 or 443 is used if <paramref name="url"/> includes
-              no port. Port 443 is used if the scheme of <paramref name="url"/>
-              is wss; otherwise, port 80 is used.
-              </para>
-              <para>
-              The new instance provides secure connections if the scheme of
-              <paramref name="url"/> is wss.
-              </para>
-            </remarks>
-            <param name="url">
-            A <see cref="T:System.String"/> that represents the WebSocket URL of the server.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="url"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="url"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="url"/> is invalid.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.#ctor(System.Int32,System.Boolean)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> class
-            with the specified <paramref name="port"/> and <paramref name="secure"/>.
-            </summary>
-            <remarks>
-            The new instance listens for incoming handshake requests on
-            <see cref="F:System.Net.IPAddress.Any"/> and <paramref name="port"/>.
-            </remarks>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <param name="secure">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if the new instance provides
-            secure connections; otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.#ctor(System.Net.IPAddress,System.Int32)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> class
-            with the specified <paramref name="address"/> and <paramref name="port"/>.
-            </summary>
-            <remarks>
-              <para>
-              The new instance listens for incoming handshake requests on
-              <paramref name="address"/> and <paramref name="port"/>.
-              </para>
-              <para>
-              It provides secure connections if <paramref name="port"/> is 443.
-              </para>
-            </remarks>
-            <param name="address">
-            A <see cref="T:System.Net.IPAddress"/> that represents the local
-            IP address on which to listen.
-            </param>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="address"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="address"/> is not a local IP address.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.#ctor(System.Net.IPAddress,System.Int32,System.Boolean)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> class
-            with the specified <paramref name="address"/>, <paramref name="port"/>,
-            and <paramref name="secure"/>.
-            </summary>
-            <remarks>
-            The new instance listens for incoming handshake requests on
-            <paramref name="address"/> and <paramref name="port"/>.
-            </remarks>
-            <param name="address">
-            A <see cref="T:System.Net.IPAddress"/> that represents the local
-            IP address on which to listen.
-            </param>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <param name="secure">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if the new instance provides
-            secure connections; otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="address"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="address"/> is not a local IP address.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.Address">
-            <summary>
-            Gets the IP address of the server.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPAddress"/> that represents the local
-            IP address on which to listen for incoming handshake requests.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.AllowForwardedRequest">
-            <summary>
-            Gets or sets a value indicating whether the server accepts every
-            handshake request without checking the request URI.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if the server accepts every handshake request without
-              checking the request URI; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.AuthenticationSchemes">
-            <summary>
-            Gets or sets the scheme used to authenticate the clients.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.AuthenticationSchemes"/>
-              enum values.
-              </para>
-              <para>
-              It represents the scheme used to authenticate the clients.
-              </para>
-              <para>
-              The default value is
-              <see cref="F:WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.IsListening">
-            <summary>
-            Gets a value indicating whether the server has started.
-            </summary>
-            <value>
-            <c>true</c> if the server has started; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.IsSecure">
-            <summary>
-            Gets a value indicating whether secure connections are provided.
-            </summary>
-            <value>
-            <c>true</c> if this instance provides secure connections; otherwise,
-            <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.KeepClean">
-            <summary>
-            Gets or sets a value indicating whether the server cleans up
-            the inactive sessions periodically.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if the server cleans up the inactive sessions every
-              60 seconds; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>true</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.Log">
-            <summary>
-            Gets the logging function for the server.
-            </summary>
-            <remarks>
-            The default logging level is <see cref="F:WebSocketSharp.LogLevel.Error"/>.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Logger"/> that provides the logging function.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.Port">
-            <summary>
-            Gets the port of the server.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen for incoming handshake requests.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.Realm">
-            <summary>
-            Gets or sets the realm used for authentication.
-            </summary>
-            <remarks>
-              <para>
-              "SECRET AREA" is used as the realm if the value is
-              <see langword="null"/> or an empty string.
-              </para>
-              <para>
-              The set operation does nothing if the server has
-              already started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> or <see langword="null"/> by default.
-              </para>
-              <para>
-              That string represents the name of the realm.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.ReuseAddress">
-            <summary>
-            Gets or sets a value indicating whether the server is allowed to
-            be bound to an address that is already in use.
-            </summary>
-            <remarks>
-              <para>
-              You should set this property to <c>true</c> if you would
-              like to resolve to wait for socket in TIME_WAIT state.
-              </para>
-              <para>
-              The set operation does nothing if the server has already
-              started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if the server is allowed to be bound to an address
-              that is already in use; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.SslConfiguration">
-            <summary>
-            Gets the configuration for secure connection.
-            </summary>
-            <remarks>
-            This configuration will be referenced when attempts to start,
-            so it must be configured before the start method is called.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.ServerSslConfiguration"/> that represents
-            the configuration used to provide secure connections.
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not provide secure connections.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.UserCredentialsFinder">
-            <summary>
-            Gets or sets the delegate used to find the credentials
-            for an identity.
-            </summary>
-            <remarks>
-              <para>
-              No credentials are found if the method invoked by
-              the delegate returns <see langword="null"/> or
-              the value is <see langword="null"/>.
-              </para>
-              <para>
-              The set operation does nothing if the server has
-              already started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              A <c>Func&lt;<see cref="T:System.Security.Principal.IIdentity"/>,
-              <see cref="T:WebSocketSharp.Net.NetworkCredential"/>&gt;</c> delegate or
-              <see langword="null"/> if not needed.
-              </para>
-              <para>
-              That delegate invokes the method called for finding
-              the credentials used to authenticate a client.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.WaitTime">
-            <summary>
-            Gets or sets the time to wait for the response to the WebSocket Ping or
-            Close.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.TimeSpan"/> to wait for the response.
-              </para>
-              <para>
-              The default value is the same as 1 second.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is zero or less.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServer.WebSocketServices">
-            <summary>
-            Gets the management function for the WebSocket services
-            provided by the server.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Server.WebSocketServiceManager"/> that manages
-            the WebSocket services provided by the server.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.AddWebSocketService``1(System.String,System.Func{``0})">
-            <summary>
-            Adds a WebSocket service with the specified behavior, path,
-            and delegate.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <param name="creator">
-              <para>
-              A <c>Func&lt;TBehavior&gt;</c> delegate.
-              </para>
-              <para>
-              It invokes the method called when creating a new session
-              instance for the service.
-              </para>
-              <para>
-              The method must create a new instance of the specified
-              behavior class and return it.
-              </para>
-            </param>
-            <typeparam name="TBehavior">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="path"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="creator"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.AddWebSocketService``1(System.String)">
-            <summary>
-            Adds a WebSocket service with the specified behavior and path.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <typeparam name="TBehaviorWithNew">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-              <para>
-              And also, it must have a public parameterless constructor.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.AddWebSocketService``1(System.String,System.Action{``0})">
-            <summary>
-            Adds a WebSocket service with the specified behavior, path,
-            and delegate.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <param name="initializer">
-              <para>
-              An <c>Action&lt;TBehaviorWithNew&gt;</c> delegate or
-              <see langword="null"/> if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when initializing
-              a new session instance for the service.
-              </para>
-            </param>
-            <typeparam name="TBehaviorWithNew">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-              <para>
-              And also, it must have a public parameterless constructor.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.RemoveWebSocketService(System.String)">
-            <summary>
-            Removes a WebSocket service with the specified path.
-            </summary>
-            <remarks>
-            The service is stopped with close status 1001 (going away)
-            if it has already started.
-            </remarks>
-            <returns>
-            <c>true</c> if the service is successfully found and removed;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to remove.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.Start">
-            <summary>
-            Starts receiving incoming handshake requests.
-            </summary>
-            <remarks>
-            This method does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              There is no server certificate for secure connection.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The underlying <see cref="T:System.Net.Sockets.TcpListener"/> has failed to start.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.Stop">
-            <summary>
-            Stops receiving incoming handshake requests.
-            </summary>
-            <exception cref="T:System.InvalidOperationException">
-            The underlying <see cref="T:System.Net.Sockets.TcpListener"/> has failed to stop.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.Stop(System.UInt16,System.String)">
-            <summary>
-            Stops receiving incoming handshake requests and closes each connection
-            with the specified code and reason.
-            </summary>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The underlying <see cref="T:System.Net.Sockets.TcpListener"/> has failed to stop.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServer.Stop(WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Stops receiving incoming handshake requests and closes each connection
-            with the specified code and reason.
-            </summary>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The underlying <see cref="T:System.Net.Sockets.TcpListener"/> has failed to stop.
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Server.HttpServer">
-            <summary>
-            Provides a simple HTTP server that allows to accept
-            WebSocket handshake requests.
-            </summary>
-            <remarks>
-            This class can provide multiple WebSocket services.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.HttpServer"/> class.
-            </summary>
-            <remarks>
-            The new instance listens for incoming requests on
-            <see cref="F:System.Net.IPAddress.Any"/> and port 80.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.#ctor(System.Int32)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.HttpServer"/> class with
-            the specified <paramref name="port"/>.
-            </summary>
-            <remarks>
-              <para>
-              The new instance listens for incoming requests on
-              <see cref="F:System.Net.IPAddress.Any"/> and <paramref name="port"/>.
-              </para>
-              <para>
-              It provides secure connections if <paramref name="port"/> is 443.
-              </para>
-            </remarks>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.#ctor(System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.HttpServer"/> class with
-            the specified <paramref name="url"/>.
-            </summary>
-            <remarks>
-              <para>
-              The new instance listens for incoming requests on the IP address of the
-              host of <paramref name="url"/> and the port of <paramref name="url"/>.
-              </para>
-              <para>
-              Either port 80 or 443 is used if <paramref name="url"/> includes
-              no port. Port 443 is used if the scheme of <paramref name="url"/>
-              is https; otherwise, port 80 is used.
-              </para>
-              <para>
-              The new instance provides secure connections if the scheme of
-              <paramref name="url"/> is https.
-              </para>
-            </remarks>
-            <param name="url">
-            A <see cref="T:System.String"/> that represents the HTTP URL of the server.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="url"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="url"/> is empty.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="url"/> is invalid.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.#ctor(System.Int32,System.Boolean)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.HttpServer"/> class with
-            the specified <paramref name="port"/> and <paramref name="secure"/>.
-            </summary>
-            <remarks>
-            The new instance listens for incoming requests on
-            <see cref="F:System.Net.IPAddress.Any"/> and <paramref name="port"/>.
-            </remarks>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <param name="secure">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if the new instance provides
-            secure connections; otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.#ctor(System.Net.IPAddress,System.Int32)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.HttpServer"/> class with
-            the specified <paramref name="address"/> and <paramref name="port"/>.
-            </summary>
-            <remarks>
-              <para>
-              The new instance listens for incoming requests on
-              <paramref name="address"/> and <paramref name="port"/>.
-              </para>
-              <para>
-              It provides secure connections if <paramref name="port"/> is 443.
-              </para>
-            </remarks>
-            <param name="address">
-            A <see cref="T:System.Net.IPAddress"/> that represents
-            the local IP address on which to listen.
-            </param>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="address"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="address"/> is not a local IP address.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.#ctor(System.Net.IPAddress,System.Int32,System.Boolean)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.HttpServer"/> class with
-            the specified <paramref name="address"/>, <paramref name="port"/>,
-            and <paramref name="secure"/>.
-            </summary>
-            <remarks>
-            The new instance listens for incoming requests on
-            <paramref name="address"/> and <paramref name="port"/>.
-            </remarks>
-            <param name="address">
-            A <see cref="T:System.Net.IPAddress"/> that represents
-            the local IP address on which to listen.
-            </param>
-            <param name="port">
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen.
-            </param>
-            <param name="secure">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if the new instance provides
-            secure connections; otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="address"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="address"/> is not a local IP address.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="port"/> is less than 1 or greater than 65535.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.Address">
-            <summary>
-            Gets the IP address of the server.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPAddress"/> that represents the local
-            IP address on which to listen for incoming requests.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.AuthenticationSchemes">
-            <summary>
-            Gets or sets the scheme used to authenticate the clients.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already
-            started or it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.AuthenticationSchemes"/>
-              enum values.
-              </para>
-              <para>
-              It represents the scheme used to authenticate the clients.
-              </para>
-              <para>
-              The default value is
-              <see cref="F:WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.DocumentRootPath">
-            <summary>
-            Gets or sets the path to the document folder of the server.
-            </summary>
-            <remarks>
-              <para>
-              '/' or '\' is trimmed from the end of the value if any.
-              </para>
-              <para>
-              The set operation does nothing if the server has already
-              started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents a path to the folder
-              from which to find the requested file.
-              </para>
-              <para>
-              The default value is "./Public".
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentNullException">
-            The value specified for a set operation is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The value specified for a set operation is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value specified for a set operation is an invalid path string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value specified for a set operation is an absolute root.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.IsListening">
-            <summary>
-            Gets a value indicating whether the server has started.
-            </summary>
-            <value>
-            <c>true</c> if the server has started; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.IsSecure">
-            <summary>
-            Gets a value indicating whether secure connections are provided.
-            </summary>
-            <value>
-            <c>true</c> if this instance provides secure connections; otherwise,
-            <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.KeepClean">
-            <summary>
-            Gets or sets a value indicating whether the server cleans up
-            the inactive sessions periodically.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already
-            started or it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if the server cleans up the inactive sessions
-              every 60 seconds; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>true</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.Log">
-            <summary>
-            Gets the logging function for the server.
-            </summary>
-            <remarks>
-            The default logging level is <see cref="F:WebSocketSharp.LogLevel.Error"/>.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Logger"/> that provides the logging function.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.Port">
-            <summary>
-            Gets the port of the server.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of the port
-            on which to listen for incoming requests.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.Realm">
-            <summary>
-            Gets or sets the realm used for authentication.
-            </summary>
-            <remarks>
-              <para>
-              "SECRET AREA" is used as the realm if the value is
-              <see langword="null"/> or an empty string.
-              </para>
-              <para>
-              The set operation does nothing if the server has
-              already started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> or <see langword="null"/> by default.
-              </para>
-              <para>
-              That string represents the name of the realm.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.ReuseAddress">
-            <summary>
-            Gets or sets a value indicating whether the server is allowed to
-            be bound to an address that is already in use.
-            </summary>
-            <remarks>
-              <para>
-              You should set this property to <c>true</c> if you would
-              like to resolve to wait for socket in TIME_WAIT state.
-              </para>
-              <para>
-              The set operation does nothing if the server has already
-              started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if the server is allowed to be bound to an address
-              that is already in use; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.SslConfiguration">
-            <summary>
-            Gets the configuration for secure connection.
-            </summary>
-            <remarks>
-            This configuration will be referenced when attempts to start,
-            so it must be configured before the start method is called.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.ServerSslConfiguration"/> that represents
-            the configuration used to provide secure connections.
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not provide secure connections.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.UserCredentialsFinder">
-            <summary>
-            Gets or sets the delegate used to find the credentials
-            for an identity.
-            </summary>
-            <remarks>
-              <para>
-              No credentials are found if the method invoked by
-              the delegate returns <see langword="null"/> or
-              the value is <see langword="null"/>.
-              </para>
-              <para>
-              The set operation does nothing if the server has
-              already started or it is shutting down.
-              </para>
-            </remarks>
-            <value>
-              <para>
-              A <c>Func&lt;<see cref="T:System.Security.Principal.IIdentity"/>,
-              <see cref="T:WebSocketSharp.Net.NetworkCredential"/>&gt;</c> delegate or
-              <see langword="null"/> if not needed.
-              </para>
-              <para>
-              That delegate invokes the method called for finding
-              the credentials used to authenticate a client.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.WaitTime">
-            <summary>
-            Gets or sets the time to wait for the response to the WebSocket Ping or
-            Close.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.TimeSpan"/> to wait for the response.
-              </para>
-              <para>
-              The default value is the same as 1 second.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is zero or less.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpServer.WebSocketServices">
-            <summary>
-            Gets the management function for the WebSocket services
-            provided by the server.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Server.WebSocketServiceManager"/> that manages
-            the WebSocket services provided by the server.
-            </value>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnConnect">
-            <summary>
-            Occurs when the server receives an HTTP CONNECT request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnDelete">
-            <summary>
-            Occurs when the server receives an HTTP DELETE request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnGet">
-            <summary>
-            Occurs when the server receives an HTTP GET request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnHead">
-            <summary>
-            Occurs when the server receives an HTTP HEAD request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnOptions">
-            <summary>
-            Occurs when the server receives an HTTP OPTIONS request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnPost">
-            <summary>
-            Occurs when the server receives an HTTP POST request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnPut">
-            <summary>
-            Occurs when the server receives an HTTP PUT request.
-            </summary>
-        </member>
-        <member name="E:WebSocketSharp.Server.HttpServer.OnTrace">
-            <summary>
-            Occurs when the server receives an HTTP TRACE request.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.AddWebSocketService``1(System.String,System.Func{``0})">
-            <summary>
-            Adds a WebSocket service with the specified behavior, path,
-            and delegate.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <param name="creator">
-              <para>
-              A <c>Func&lt;TBehavior&gt;</c> delegate.
-              </para>
-              <para>
-              It invokes the method called when creating a new session
-              instance for the service.
-              </para>
-              <para>
-              The method must create a new instance of the specified
-              behavior class and return it.
-              </para>
-            </param>
-            <typeparam name="TBehavior">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="path"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="creator"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.AddWebSocketService``1(System.String)">
-            <summary>
-            Adds a WebSocket service with the specified behavior and path.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <typeparam name="TBehaviorWithNew">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-              <para>
-              And also, it must have a public parameterless constructor.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.AddWebSocketService``1(System.String,System.Action{``0})">
-            <summary>
-            Adds a WebSocket service with the specified behavior, path,
-            and delegate.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <param name="initializer">
-              <para>
-              An <c>Action&lt;TBehaviorWithNew&gt;</c> delegate or
-              <see langword="null"/> if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when initializing
-              a new session instance for the service.
-              </para>
-            </param>
-            <typeparam name="TBehaviorWithNew">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-              <para>
-              And also, it must have a public parameterless constructor.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.GetFile(System.String)">
-            <summary>
-            Gets the contents of the specified file from the document
-            folder of the server.
-            </summary>
-            <returns>
-              <para>
-              An array of <see cref="T:System.Byte"/> or <see langword="null"/>
-              if it fails.
-              </para>
-              <para>
-              That array represents the contents of the file.
-              </para>
-            </returns>
-            <param name="path">
-            A <see cref="T:System.String"/> that represents a virtual path to
-            find the file from the document folder.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> contains "..".
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.RemoveWebSocketService(System.String)">
-            <summary>
-            Removes a WebSocket service with the specified path.
-            </summary>
-            <remarks>
-            The service is stopped with close status 1001 (going away)
-            if it has already started.
-            </remarks>
-            <returns>
-            <c>true</c> if the service is successfully found and removed;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to remove.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.Start">
-            <summary>
-            Starts receiving incoming requests.
-            </summary>
-            <remarks>
-            This method does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              There is no server certificate for secure connection.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The underlying <see cref="T:WebSocketSharp.Net.HttpListener"/> has failed to start.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.Stop">
-            <summary>
-            Stops receiving incoming requests.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.Stop(System.UInt16,System.String)">
-            <summary>
-            Stops receiving incoming requests and closes each connection.
-            </summary>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the WebSocket connection close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the WebSocket
-              connection close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpServer.Stop(WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Stops receiving incoming requests and closes each connection.
-            </summary>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the WebSocket
-              connection close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the WebSocket
-              connection close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Server.WebSocketServiceHost">
-            <summary>
-            Exposes the methods and properties used to access the information in
-            a WebSocket service provided by the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> or
-            <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </summary>
-            <remarks>
-            This class is an abstract class.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceHost.#ctor(System.String,WebSocketSharp.Logger)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketServiceHost"/> class
-            with the specified <paramref name="path"/> and <paramref name="log"/>.
-            </summary>
-            <param name="path">
-            A <see cref="T:System.String"/> that represents the absolute path to the service.
-            </param>
-            <param name="log">
-            A <see cref="T:WebSocketSharp.Logger"/> that represents the logging function for the service.
-            </param>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceHost.Log">
-            <summary>
-            Gets the logging function for the service.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Logger"/> that provides the logging function.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceHost.KeepClean">
-            <summary>
-            Gets or sets a value indicating whether the service cleans up
-            the inactive sessions periodically.
-            </summary>
-            <remarks>
-            The set operation does nothing if the service has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-            <c>true</c> if the service cleans up the inactive sessions every
-            60 seconds; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceHost.Path">
-            <summary>
-            Gets the path to the service.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the absolute path to
-            the service.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceHost.Sessions">
-            <summary>
-            Gets the management function for the sessions in the service.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Server.WebSocketSessionManager"/> that manages the sessions in
-            the service.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceHost.BehaviorType">
-            <summary>
-            Gets the <see cref="T:System.Type"/> of the behavior of the service.
-            </summary>
-            <value>
-            A <see cref="T:System.Type"/> that represents the type of the behavior of
-            the service.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceHost.WaitTime">
-            <summary>
-            Gets or sets the time to wait for the response to the WebSocket Ping or
-            Close.
-            </summary>
-            <remarks>
-            The set operation does nothing if the service has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-            A <see cref="T:System.TimeSpan"/> to wait for the response.
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is zero or less.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceHost.CreateSession">
-            <summary>
-            Creates a new session for the service.
-            </summary>
-            <returns>
-            A <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> instance that represents
-            the new session.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Server.HttpRequestEventArgs">
-            <summary>
-            Represents the event data for the HTTP request events of
-            the <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </summary>
-            <remarks>
-              <para>
-              An HTTP request event occurs when the <see cref="T:WebSocketSharp.Server.HttpServer"/>
-              receives an HTTP request.
-              </para>
-              <para>
-              You should access the <see cref="P:WebSocketSharp.Server.HttpRequestEventArgs.Request"/> property if you would
-              like to get the request data sent from a client.
-              </para>
-              <para>
-              And you should access the <see cref="P:WebSocketSharp.Server.HttpRequestEventArgs.Response"/> property if you would
-              like to get the response data to return to the client.
-              </para>
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpRequestEventArgs.Request">
-            <summary>
-            Gets the request data sent from a client.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.HttpListenerRequest"/> that provides the methods and
-            properties for the request data.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpRequestEventArgs.Response">
-            <summary>
-            Gets the response data to return to the client.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.HttpListenerResponse"/> that provides the methods and
-            properties for the response data.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.HttpRequestEventArgs.User">
-            <summary>
-            Gets the information for the client.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Security.Principal.IPrincipal"/> instance or <see langword="null"/>
-              if not authenticated.
-              </para>
-              <para>
-              That instance describes the identity, authentication scheme,
-              and security roles for the client.
-              </para>
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpRequestEventArgs.ReadFile(System.String)">
-            <summary>
-            Reads the specified file from the document folder of
-            the <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </summary>
-            <returns>
-              <para>
-              An array of <see cref="T:System.Byte"/> or <see langword="null"/>
-              if it fails.
-              </para>
-              <para>
-              That array receives the contents of the file.
-              </para>
-            </returns>
-            <param name="path">
-            A <see cref="T:System.String"/> that represents a virtual path to
-            find the file from the document folder.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> contains "..".
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.HttpRequestEventArgs.TryReadFile(System.String,System.Byte[]@)">
-            <summary>
-            Tries to read the specified file from the document folder of
-            the <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </summary>
-            <returns>
-            <c>true</c> if it succeeds to read; otherwise, <c>false</c>.
-            </returns>
-            <param name="path">
-            A <see cref="T:System.String"/> that represents a virtual path to
-            find the file from the document folder.
-            </param>
-            <param name="contents">
-              <para>
-              When this method returns, an array of <see cref="T:System.Byte"/> or
-              <see langword="null"/> if it fails.
-              </para>
-              <para>
-              That array receives the contents of the file.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> contains "..".
-              </para>
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Server.IWebSocketSession">
-            <summary>
-            Exposes the access to the information in a WebSocket session.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Server.IWebSocketSession.ConnectionState">
-            <summary>
-            Gets the current state of the WebSocket connection for the session.
-            </summary>
-            <value>
-              <para>
-              One of the <see cref="T:WebSocketSharp.WebSocketState"/> enum values.
-              </para>
-              <para>
-              It indicates the current state of the connection.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.IWebSocketSession.Context">
-            <summary>
-            Gets the information in the WebSocket handshake request.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.WebSockets.WebSocketContext"/> instance that provides the access to
-            the information in the handshake request.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.IWebSocketSession.ID">
-            <summary>
-            Gets the unique ID of the session.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the unique ID of the session.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.IWebSocketSession.Protocol">
-            <summary>
-            Gets the name of the WebSocket subprotocol for the session.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the name of the subprotocol
-            if present.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.IWebSocketSession.StartTime">
-            <summary>
-            Gets the time that the session has started.
-            </summary>
-            <value>
-            A <see cref="T:System.DateTime"/> that represents the time that the session
-            has started.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.Server.WebSocketSessionManager">
-            <summary>
-            Provides the management function for the sessions in a WebSocket service.
-            </summary>
-            <remarks>
-            This class manages the sessions in a WebSocket service provided by
-            the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> or <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.ActiveIDs">
-            <summary>
-            Gets the IDs for the active sessions in the WebSocket service.
-            </summary>
-            <value>
-              <para>
-              An <c>IEnumerable&lt;string&gt;</c> instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the IDs for the active sessions.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.Count">
-            <summary>
-            Gets the number of the sessions in the WebSocket service.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of the sessions.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.IDs">
-            <summary>
-            Gets the IDs for the sessions in the WebSocket service.
-            </summary>
-            <value>
-              <para>
-              An <c>IEnumerable&lt;string&gt;</c> instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the IDs for the sessions.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.InactiveIDs">
-            <summary>
-            Gets the IDs for the inactive sessions in the WebSocket service.
-            </summary>
-            <value>
-              <para>
-              An <c>IEnumerable&lt;string&gt;</c> instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the IDs for the inactive sessions.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.Item(System.String)">
-            <summary>
-            Gets the session instance with <paramref name="id"/>.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Server.IWebSocketSession"/> instance or <see langword="null"/>
-              if not found.
-              </para>
-              <para>
-              The session instance provides the function to access the information
-              in the session.
-              </para>
-            </value>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session to find.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="id"/> is an empty string.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.KeepClean">
-            <summary>
-            Gets or sets a value indicating whether the inactive sessions in
-            the WebSocket service are cleaned up periodically.
-            </summary>
-            <remarks>
-            The set operation does nothing if the service has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-            <c>true</c> if the inactive sessions are cleaned up every 60 seconds;
-            otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.Sessions">
-            <summary>
-            Gets the session instances in the WebSocket service.
-            </summary>
-            <value>
-              <para>
-              An <c>IEnumerable&lt;IWebSocketSession&gt;</c> instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the session instances.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketSessionManager.WaitTime">
-            <summary>
-            Gets or sets the time to wait for the response to the WebSocket Ping or
-            Close.
-            </summary>
-            <remarks>
-            The set operation does nothing if the service has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-            A <see cref="T:System.TimeSpan"/> to wait for the response.
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is zero or less.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.Broadcast(System.Byte[])">
-            <summary>
-            Sends <paramref name="data"/> to every client in the WebSocket service.
-            </summary>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.Broadcast(System.String)">
-            <summary>
-            Sends <paramref name="data"/> to every client in the WebSocket service.
-            </summary>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.Broadcast(System.IO.Stream,System.Int32)">
-            <summary>
-            Sends the data from <paramref name="stream"/> to every client in
-            the WebSocket service.
-            </summary>
-            <remarks>
-            The data is sent as the binary data.
-            </remarks>
-            <param name="stream">
-            A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.BroadcastAsync(System.Byte[],System.Action)">
-            <summary>
-            Sends <paramref name="data"/> asynchronously to every client in
-            the WebSocket service.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <see cref="T:System.Action"/> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.BroadcastAsync(System.String,System.Action)">
-            <summary>
-            Sends <paramref name="data"/> asynchronously to every client in
-            the WebSocket service.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <see cref="T:System.Action"/> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.BroadcastAsync(System.IO.Stream,System.Int32,System.Action)">
-            <summary>
-            Sends the data from <paramref name="stream"/> asynchronously to
-            every client in the WebSocket service.
-            </summary>
-            <remarks>
-              <para>
-              The data is sent as the binary data.
-              </para>
-              <para>
-              This method does not wait for the send to be complete.
-              </para>
-            </remarks>
-            <param name="stream">
-            A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <see cref="T:System.Action"/> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.Broadping">
-            <summary>
-            Sends a ping to every client in the WebSocket service.
-            </summary>
-            <returns>
-              <para>
-              A <c>Dictionary&lt;string, bool&gt;</c>.
-              </para>
-              <para>
-              It represents a collection of pairs of a session ID and
-              a value indicating whether a pong has been received from
-              the client within a time.
-              </para>
-            </returns>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.Broadping(System.String)">
-            <summary>
-            Sends a ping with <paramref name="message"/> to every client in
-            the WebSocket service.
-            </summary>
-            <returns>
-              <para>
-              A <c>Dictionary&lt;string, bool&gt;</c>.
-              </para>
-              <para>
-              It represents a collection of pairs of a session ID and
-              a value indicating whether a pong has been received from
-              the client within a time.
-              </para>
-            </returns>
-            <param name="message">
-              <para>
-              A <see cref="T:System.String"/> that represents the message to send.
-              </para>
-              <para>
-              The size must be 125 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="message"/> could not be UTF-8-encoded.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="message"/> is greater than 125 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.CloseSession(System.String)">
-            <summary>
-            Closes the specified session.
-            </summary>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session to close.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="id"/> is an empty string.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The session could not be found.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.CloseSession(System.String,System.UInt16,System.String)">
-            <summary>
-            Closes the specified session with <paramref name="code"/> and
-            <paramref name="reason"/>.
-            </summary>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session to close.
-            </param>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is
-              <paramref name="reason"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The session could not be found.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.CloseSession(System.String,WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Closes the specified session with <paramref name="code"/> and
-            <paramref name="reason"/>.
-            </summary>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session to close.
-            </param>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is
-              <paramref name="reason"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The session could not be found.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.PingTo(System.String)">
-            <summary>
-            Sends a ping to the client using the specified session.
-            </summary>
-            <returns>
-            <c>true</c> if the send has done with no error and a pong has been
-            received from the client within a time; otherwise, <c>false</c>.
-            </returns>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="id"/> is an empty string.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The session could not be found.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.PingTo(System.String,System.String)">
-            <summary>
-            Sends a ping with <paramref name="message"/> to the client using
-            the specified session.
-            </summary>
-            <returns>
-            <c>true</c> if the send has done with no error and a pong has been
-            received from the client within a time; otherwise, <c>false</c>.
-            </returns>
-            <param name="message">
-              <para>
-              A <see cref="T:System.String"/> that represents the message to send.
-              </para>
-              <para>
-              The size must be 125 bytes or less in UTF-8.
-              </para>
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="message"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The session could not be found.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="message"/> is greater than 125 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.SendTo(System.Byte[],System.String)">
-            <summary>
-            Sends <paramref name="data"/> to the client using the specified session.
-            </summary>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="id"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="data"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="id"/> is an empty string.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              The session could not be found.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The current state of the WebSocket connection is not Open.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.SendTo(System.String,System.String)">
-            <summary>
-            Sends <paramref name="data"/> to the client using the specified session.
-            </summary>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="id"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="data"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="data"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              The session could not be found.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The current state of the WebSocket connection is not Open.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.SendTo(System.IO.Stream,System.Int32,System.String)">
-            <summary>
-            Sends the data from <paramref name="stream"/> to the client using
-            the specified session.
-            </summary>
-            <remarks>
-            The data is sent as the binary data.
-            </remarks>
-            <param name="stream">
-            A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="id"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="stream"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              The session could not be found.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The current state of the WebSocket connection is not Open.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.SendToAsync(System.Byte[],System.String,System.Action{System.Boolean})">
-            <summary>
-            Sends <paramref name="data"/> asynchronously to the client using
-            the specified session.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="id"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="data"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="id"/> is an empty string.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              The session could not be found.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The current state of the WebSocket connection is not Open.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.SendToAsync(System.String,System.String,System.Action{System.Boolean})">
-            <summary>
-            Sends <paramref name="data"/> asynchronously to the client using
-            the specified session.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="id"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="data"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="data"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              The session could not be found.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The current state of the WebSocket connection is not Open.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.SendToAsync(System.IO.Stream,System.Int32,System.String,System.Action{System.Boolean})">
-            <summary>
-            Sends the data from <paramref name="stream"/> asynchronously to
-            the client using the specified session.
-            </summary>
-            <remarks>
-              <para>
-              The data is sent as the binary data.
-              </para>
-              <para>
-              This method does not wait for the send to be complete.
-              </para>
-            </remarks>
-            <param name="stream">
-            A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-              <para>
-              <paramref name="id"/> is <see langword="null"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="stream"/> is <see langword="null"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="id"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-              <para>
-              The session could not be found.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The current state of the WebSocket connection is not Open.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.Sweep">
-            <summary>
-            Cleans up the inactive sessions in the WebSocket service.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketSessionManager.TryGetSession(System.String,WebSocketSharp.Server.IWebSocketSession@)">
-            <summary>
-            Tries to get the session instance with <paramref name="id"/>.
-            </summary>
-            <returns>
-            <c>true</c> if the session is successfully found; otherwise,
-            <c>false</c>.
-            </returns>
-            <param name="id">
-            A <see cref="T:System.String"/> that represents the ID of the session to find.
-            </param>
-            <param name="session">
-              <para>
-              When this method returns, a <see cref="T:WebSocketSharp.Server.IWebSocketSession"/>
-              instance or <see langword="null"/> if not found.
-              </para>
-              <para>
-              The session instance provides the function to access
-              the information in the session.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="id"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="id"/> is an empty string.
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Server.WebSocketServiceManager">
-            <summary>
-            Provides the management function for the WebSocket services.
-            </summary>
-            <remarks>
-            This class manages the WebSocket services provided by
-            the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> or <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.Count">
-            <summary>
-            Gets the number of the WebSocket services.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of the services.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.Hosts">
-            <summary>
-            Gets the host instances for the WebSocket services.
-            </summary>
-            <value>
-              <para>
-              An <c>IEnumerable&lt;WebSocketServiceHost&gt;</c> instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the host instances.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.Item(System.String)">
-            <summary>
-            Gets the host instance for a WebSocket service with the specified path.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Server.WebSocketServiceHost"/> instance or
-              <see langword="null"/> if not found.
-              </para>
-              <para>
-              The host instance provides the function to access
-              the information in the service.
-              </para>
-            </value>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to find.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is empty.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.KeepClean">
-            <summary>
-            Gets or sets a value indicating whether the inactive sessions in
-            the WebSocket services are cleaned up periodically.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-            <c>true</c> if the inactive sessions are cleaned up every 60 seconds;
-            otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.Paths">
-            <summary>
-            Gets the paths for the WebSocket services.
-            </summary>
-            <value>
-              <para>
-              An <c>IEnumerable&lt;string&gt;</c> instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the paths.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.SessionCount">
-            <summary>
-            Gets the total number of the sessions in the WebSocket services.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the total number of
-            the sessions in the services.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketServiceManager.WaitTime">
-            <summary>
-            Gets or sets the time to wait for the response to the WebSocket Ping or
-            Close.
-            </summary>
-            <remarks>
-            The set operation does nothing if the server has already started or
-            it is shutting down.
-            </remarks>
-            <value>
-            A <see cref="T:System.TimeSpan"/> to wait for the response.
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is zero or less.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.AddService``1(System.String,System.Action{``0})">
-            <summary>
-            Adds a WebSocket service with the specified behavior, path,
-            and delegate.
-            </summary>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to add.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <param name="initializer">
-              <para>
-              An <c>Action&lt;TBehavior&gt;</c> delegate or
-              <see langword="null"/> if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when initializing
-              a new session instance for the service.
-              </para>
-            </param>
-            <typeparam name="TBehavior">
-              <para>
-              The type of the behavior for the service.
-              </para>
-              <para>
-              It must inherit the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-              </para>
-              <para>
-              And also, it must have a public parameterless constructor.
-              </para>
-            </typeparam>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is empty.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is already in use.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.Broadcast(System.Byte[])">
-            <summary>
-            Sends <paramref name="data"/> to every client in the WebSocket services.
-            </summary>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.Broadcast(System.String)">
-            <summary>
-            Sends <paramref name="data"/> to every client in the WebSocket services.
-            </summary>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.BroadcastAsync(System.Byte[],System.Action)">
-            <summary>
-            Sends <paramref name="data"/> asynchronously to every client in
-            the WebSocket services.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <see cref="T:System.Action"/> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.BroadcastAsync(System.String,System.Action)">
-            <summary>
-            Sends <paramref name="data"/> asynchronously to every client in
-            the WebSocket services.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <see cref="T:System.Action"/> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.BroadcastAsync(System.IO.Stream,System.Int32,System.Action)">
-            <summary>
-            Sends the data from <paramref name="stream"/> asynchronously to
-            every client in the WebSocket services.
-            </summary>
-            <remarks>
-              <para>
-              The data is sent as the binary data.
-              </para>
-              <para>
-              This method does not wait for the send to be complete.
-              </para>
-            </remarks>
-            <param name="stream">
-            A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <see cref="T:System.Action"/> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.Broadping">
-            <summary>
-            Sends a ping to every client in the WebSocket services.
-            </summary>
-            <returns>
-              <para>
-              A <c>Dictionary&lt;string, Dictionary&lt;string, bool&gt;&gt;</c>.
-              </para>
-              <para>
-              It represents a collection of pairs of a service path and another
-              collection of pairs of a session ID and a value indicating whether
-              a pong has been received from the client within a time.
-              </para>
-            </returns>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.Broadping(System.String)">
-            <summary>
-            Sends a ping with <paramref name="message"/> to every client in
-            the WebSocket services.
-            </summary>
-            <returns>
-              <para>
-              A <c>Dictionary&lt;string, Dictionary&lt;string, bool&gt;&gt;</c>.
-              </para>
-              <para>
-              It represents a collection of pairs of a service path and another
-              collection of pairs of a session ID and a value indicating whether
-              a pong has been received from the client within a time.
-              </para>
-            </returns>
-            <param name="message">
-              <para>
-              A <see cref="T:System.String"/> that represents the message to send.
-              </para>
-              <para>
-              The size must be 125 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the manager is not Start.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="message"/> could not be UTF-8-encoded.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="message"/> is greater than 125 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.Clear">
-            <summary>
-            Removes all WebSocket services managed by the manager.
-            </summary>
-            <remarks>
-            A service is stopped with close status 1001 (going away)
-            if it has already started.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.RemoveService(System.String)">
-            <summary>
-            Removes a WebSocket service with the specified path.
-            </summary>
-            <remarks>
-            The service is stopped with close status 1001 (going away)
-            if it has already started.
-            </remarks>
-            <returns>
-            <c>true</c> if the service is successfully found and removed;
-            otherwise, <c>false</c>.
-            </returns>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to remove.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is empty.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketServiceManager.TryGetServiceHost(System.String,WebSocketSharp.Server.WebSocketServiceHost@)">
-            <summary>
-            Tries to get the host instance for a WebSocket service with
-            the specified path.
-            </summary>
-            <returns>
-            <c>true</c> if the service is successfully found; otherwise,
-            <c>false</c>.
-            </returns>
-            <param name="path">
-              <para>
-              A <see cref="T:System.String"/> that represents an absolute path to
-              the service to find.
-              </para>
-              <para>
-              / is trimmed from the end of the string if present.
-              </para>
-            </param>
-            <param name="host">
-              <para>
-              When this method returns, a <see cref="T:WebSocketSharp.Server.WebSocketServiceHost"/>
-              instance or <see langword="null"/> if not found.
-              </para>
-              <para>
-              The host instance provides the function to access
-              the information in the service.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="path"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="path"/> is empty.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> is not an absolute path.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="path"/> includes either or both
-              query and fragment components.
-              </para>
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Server.WebSocketBehavior">
-            <summary>
-            Exposes a set of methods and properties used to define the behavior of
-            a WebSocket service provided by the <see cref="T:WebSocketSharp.Server.WebSocketServer"/> or
-            <see cref="T:WebSocketSharp.Server.HttpServer"/>.
-            </summary>
-            <remarks>
-            This class is an abstract class.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Server.WebSocketBehavior"/> class.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.Headers">
-            <summary>
-            Gets the HTTP headers included in a WebSocket handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the headers.
-              </para>
-              <para>
-              <see langword="null"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.Log">
-            <summary>
-            Gets the logging function.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Logger"/> that provides the logging function.
-              </para>
-              <para>
-              <see langword="null"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.QueryString">
-            <summary>
-            Gets the query string included in a WebSocket handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the query
-              parameters.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-              <para>
-              <see langword="null"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.Sessions">
-            <summary>
-            Gets the management function for the sessions in the service.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Server.WebSocketSessionManager"/> that manages the sessions in
-              the service.
-              </para>
-              <para>
-              <see langword="null"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.ConnectionState">
-            <summary>
-            Gets the current state of the WebSocket connection for a session.
-            </summary>
-            <value>
-              <para>
-              One of the <see cref="T:WebSocketSharp.WebSocketState"/> enum values.
-              </para>
-              <para>
-              It indicates the current state of the connection.
-              </para>
-              <para>
-              <see cref="F:WebSocketSharp.WebSocketState.Connecting"/> if the session has not
-              started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.Context">
-            <summary>
-            Gets the information in a WebSocket handshake request to the service.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Net.WebSockets.WebSocketContext"/> instance that provides the access to
-              the information in the handshake request.
-              </para>
-              <para>
-              <see langword="null"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.CookiesValidator">
-            <summary>
-            Gets or sets the delegate used to validate the HTTP cookies included in
-            a WebSocket handshake request to the service.
-            </summary>
-            <value>
-              <para>
-              A <c>Func&lt;CookieCollection, CookieCollection, bool&gt;</c> delegate
-              or <see langword="null"/> if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the WebSocket instance
-              for a session validates the handshake request.
-              </para>
-              <para>
-              1st <see cref="T:WebSocketSharp.Net.CookieCollection"/> parameter passed to the method
-              contains the cookies to validate if present.
-              </para>
-              <para>
-              2nd <see cref="T:WebSocketSharp.Net.CookieCollection"/> parameter passed to the method
-              receives the cookies to send to the client.
-              </para>
-              <para>
-              The method must return <c>true</c> if the cookies are valid.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.EmitOnPing">
-            <summary>
-            Gets or sets a value indicating whether the WebSocket instance for
-            a session emits the message event when receives a ping.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the WebSocket instance emits the message event
-              when receives a ping; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.ID">
-            <summary>
-            Gets the unique ID of a session.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the unique ID of the session.
-              </para>
-              <para>
-              <see langword="null"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.IgnoreExtensions">
-            <summary>
-            Gets or sets a value indicating whether the service ignores
-            the Sec-WebSocket-Extensions header included in a WebSocket
-            handshake request.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the service ignores the extensions requested
-              from a client; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.OriginValidator">
-            <summary>
-            Gets or sets the delegate used to validate the Origin header included in
-            a WebSocket handshake request to the service.
-            </summary>
-            <value>
-              <para>
-              A <c>Func&lt;string, bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the WebSocket instance
-              for a session validates the handshake request.
-              </para>
-              <para>
-              The <see cref="T:System.String"/> parameter passed to the method is the value
-              of the Origin header or <see langword="null"/> if the header is not
-              present.
-              </para>
-              <para>
-              The method must return <c>true</c> if the header value is valid.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.Protocol">
-            <summary>
-            Gets or sets the name of the WebSocket subprotocol for the service.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the name of the subprotocol.
-              </para>
-              <para>
-              The value specified for a set must be a token defined in
-              <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
-              RFC 2616</see>.
-              </para>
-              <para>
-              The default value is an empty string.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The set operation is not available if the session has already started.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            The value specified for a set operation is not a token.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Server.WebSocketBehavior.StartTime">
-            <summary>
-            Gets the time that a session has started.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.DateTime"/> that represents the time that the session
-              has started.
-              </para>
-              <para>
-              <see cref="F:System.DateTime.MaxValue"/> if the session has not started yet.
-              </para>
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Close">
-            <summary>
-            Closes the WebSocket connection for a session.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-            The session has not started yet.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Close(System.UInt16,System.String)">
-            <summary>
-            Closes the WebSocket connection for a session with the specified
-            code and reason.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The session has not started yet.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Close(WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Closes the WebSocket connection for a session with the specified
-            code and reason.
-            </summary>
-            <remarks>
-            This method does nothing if the current state of the connection is
-            Closing or Closed.
-            </remarks>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The session has not started yet.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.CloseAsync">
-            <summary>
-            Closes the WebSocket connection for a session asynchronously.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <exception cref="T:System.InvalidOperationException">
-            The session has not started yet.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.CloseAsync(System.UInt16,System.String)">
-            <summary>
-            Closes the WebSocket connection for a session asynchronously with
-            the specified code and reason.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <param name="code">
-              <para>
-              A <see cref="T:System.UInt16"/> that represents the status code indicating
-              the reason for the close.
-              </para>
-              <para>
-              The status codes are defined in
-              <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
-              Section 7.4</see> of RFC 6455.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The session has not started yet.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-              <para>
-              <paramref name="code"/> is less than 1000 or greater than 4999.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The size of <paramref name="reason"/> is greater than 123 bytes.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is 1010 (mandatory extension).
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is 1005 (no status) and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.CloseAsync(WebSocketSharp.CloseStatusCode,System.String)">
-            <summary>
-            Closes the WebSocket connection for a session asynchronously with
-            the specified code and reason.
-            </summary>
-            <remarks>
-              <para>
-              This method does not wait for the close to be complete.
-              </para>
-              <para>
-              This method does nothing if the current state of the connection is
-              Closing or Closed.
-              </para>
-            </remarks>
-            <param name="code">
-              <para>
-              One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values.
-              </para>
-              <para>
-              It represents the status code indicating the reason for the close.
-              </para>
-            </param>
-            <param name="reason">
-              <para>
-              A <see cref="T:System.String"/> that represents the reason for the close.
-              </para>
-              <para>
-              The size must be 123 bytes or less in UTF-8.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The session has not started yet.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.MandatoryExtension"/>.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="code"/> is
-              <see cref="F:WebSocketSharp.CloseStatusCode.NoStatus"/> and there is reason.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="reason"/> could not be UTF-8-encoded.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The size of <paramref name="reason"/> is greater than 123 bytes.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Error(System.String,System.Exception)">
-            <summary>
-            Calls the <see cref="M:WebSocketSharp.Server.WebSocketBehavior.OnError(WebSocketSharp.ErrorEventArgs)"/> method with the specified message.
-            </summary>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the error message.
-            </param>
-            <param name="exception">
-            An <see cref="T:System.Exception"/> instance that represents the cause of
-            the error if present.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="message"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="message"/> is an empty string.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.OnClose(WebSocketSharp.CloseEventArgs)">
-            <summary>
-            Called when the WebSocket connection for a session has been closed.
-            </summary>
-            <param name="e">
-            A <see cref="T:WebSocketSharp.CloseEventArgs"/> that represents the event data passed
-            from a <see cref="E:WebSocketSharp.WebSocket.OnClose"/> event.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.OnError(WebSocketSharp.ErrorEventArgs)">
-            <summary>
-            Called when the WebSocket instance for a session gets an error.
-            </summary>
-            <param name="e">
-            A <see cref="T:WebSocketSharp.ErrorEventArgs"/> that represents the event data passed
-            from a <see cref="E:WebSocketSharp.WebSocket.OnError"/> event.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.OnMessage(WebSocketSharp.MessageEventArgs)">
-            <summary>
-            Called when the WebSocket instance for a session receives a message.
-            </summary>
-            <param name="e">
-            A <see cref="T:WebSocketSharp.MessageEventArgs"/> that represents the event data passed
-            from a <see cref="E:WebSocketSharp.WebSocket.OnMessage"/> event.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.OnOpen">
-            <summary>
-            Called when the WebSocket connection for a session has been established.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Send(System.Byte[])">
-            <summary>
-            Sends the specified data to a client using the WebSocket connection.
-            </summary>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Send(System.IO.FileInfo)">
-            <summary>
-            Sends the specified file to a client using the WebSocket connection.
-            </summary>
-            <param name="fileInfo">
-              <para>
-              A <see cref="T:System.IO.FileInfo"/> that specifies the file to send.
-              </para>
-              <para>
-              The file is sent as the binary data.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="fileInfo"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The file does not exist.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The file could not be opened.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Send(System.String)">
-            <summary>
-            Sends the specified data to a client using the WebSocket connection.
-            </summary>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.Send(System.IO.Stream,System.Int32)">
-            <summary>
-            Sends the data from the specified stream to a client using
-            the WebSocket connection.
-            </summary>
-            <param name="stream">
-              <para>
-              A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-              </para>
-              <para>
-              The data is sent as the binary data.
-              </para>
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.SendAsync(System.Byte[],System.Action{System.Boolean})">
-            <summary>
-            Sends the specified data to a client asynchronously using
-            the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            An array of <see cref="T:System.Byte"/> that represents the binary data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.SendAsync(System.IO.FileInfo,System.Action{System.Boolean})">
-            <summary>
-            Sends the specified file to a client asynchronously using
-            the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="fileInfo">
-              <para>
-              A <see cref="T:System.IO.FileInfo"/> that specifies the file to send.
-              </para>
-              <para>
-              The file is sent as the binary data.
-              </para>
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="fileInfo"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The file does not exist.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The file could not be opened.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.SendAsync(System.String,System.Action{System.Boolean})">
-            <summary>
-            Sends the specified data to a client asynchronously using
-            the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="data">
-            A <see cref="T:System.String"/> that represents the text data to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="data"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="data"/> could not be UTF-8-encoded.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Server.WebSocketBehavior.SendAsync(System.IO.Stream,System.Int32,System.Action{System.Boolean})">
-            <summary>
-            Sends the data from the specified stream to a client asynchronously
-            using the WebSocket connection.
-            </summary>
-            <remarks>
-            This method does not wait for the send to be complete.
-            </remarks>
-            <param name="stream">
-              <para>
-              A <see cref="T:System.IO.Stream"/> instance from which to read the data to send.
-              </para>
-              <para>
-              The data is sent as the binary data.
-              </para>
-            </param>
-            <param name="length">
-            An <see cref="T:System.Int32"/> that specifies the number of bytes to send.
-            </param>
-            <param name="completed">
-              <para>
-              An <c>Action&lt;bool&gt;</c> delegate or <see langword="null"/>
-              if not needed.
-              </para>
-              <para>
-              The delegate invokes the method called when the send is complete.
-              </para>
-              <para>
-              <c>true</c> is passed to the method if the send has done with
-              no error; otherwise, <c>false</c>.
-              </para>
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The current state of the connection is not Open.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="stream"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="stream"/> cannot be read.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="length"/> is less than 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              No data could be read from <paramref name="stream"/>.
-              </para>
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Net.AuthenticationSchemes">
-            <summary>
-            Specifies the scheme for authentication.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.AuthenticationSchemes.None">
-            <summary>
-            No authentication is allowed.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.AuthenticationSchemes.Digest">
-            <summary>
-            Specifies digest authentication.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.AuthenticationSchemes.Basic">
-            <summary>
-            Specifies basic authentication.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.AuthenticationSchemes.Anonymous">
-            <summary>
-            Specifies anonymous authentication.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Net.Cookie">
-            <summary>
-            Provides a set of methods and properties used to manage an HTTP cookie.
-            </summary>
-            <remarks>
-              <para>
-              This class refers to the following specifications:
-              </para>
-              <list type="bullet">
-                <item>
-                  <term>
-                  <see href="http://web.archive.org/web/20020803110822/http://wp.netscape.com/newsref/std/cookie_spec.html">Netscape specification</see>
-                  </term>
-                </item>
-                <item>
-                  <term>
-                  <see href="https://tools.ietf.org/html/rfc2109">RFC 2109</see>
-                  </term>
-                </item>
-                <item>
-                  <term>
-                  <see href="https://tools.ietf.org/html/rfc2965">RFC 2965</see>
-                  </term>
-                </item>
-                <item>
-                  <term>
-                  <see href="https://tools.ietf.org/html/rfc6265">RFC 6265</see>
-                  </term>
-                </item>
-              </list>
-              <para>
-              This class cannot be inherited.
-              </para>
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.Cookie"/> class.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.#ctor(System.String,System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.Cookie"/> class with
-            the specified name and value.
-            </summary>
-            <param name="name">
-              <para>
-              A <see cref="T:System.String"/> that specifies the name of the cookie.
-              </para>
-              <para>
-              The name must be a token defined in
-              <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
-              RFC 2616</see>.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the cookie.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="name"/> starts with a dollar sign.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="value"/> is a string not enclosed in double quotes
-              that contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.#ctor(System.String,System.String,System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.Cookie"/> class with
-            the specified name, value, and path.
-            </summary>
-            <param name="name">
-              <para>
-              A <see cref="T:System.String"/> that specifies the name of the cookie.
-              </para>
-              <para>
-              The name must be a token defined in
-              <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
-              RFC 2616</see>.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the cookie.
-            </param>
-            <param name="path">
-            A <see cref="T:System.String"/> that specifies the value of the Path
-            attribute of the cookie.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="name"/> starts with a dollar sign.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="value"/> is a string not enclosed in double quotes
-              that contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.#ctor(System.String,System.String,System.String,System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.Cookie"/> class with
-            the specified name, value, path, and domain.
-            </summary>
-            <param name="name">
-              <para>
-              A <see cref="T:System.String"/> that specifies the name of the cookie.
-              </para>
-              <para>
-              The name must be a token defined in
-              <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
-              RFC 2616</see>.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the cookie.
-            </param>
-            <param name="path">
-            A <see cref="T:System.String"/> that specifies the value of the Path
-            attribute of the cookie.
-            </param>
-            <param name="domain">
-            A <see cref="T:System.String"/> that specifies the value of the Domain
-            attribute of the cookie.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="name"/> starts with a dollar sign.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              <paramref name="value"/> is a string not enclosed in double quotes
-              that contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Comment">
-            <summary>
-            Gets the value of the Comment attribute of the cookie.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the comment to document
-              intended use of the cookie.
-              </para>
-              <para>
-              <see langword="null"/> if not present.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.CommentUri">
-            <summary>
-            Gets the value of the CommentURL attribute of the cookie.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Uri"/> that represents the URI that provides
-              the comment to document intended use of the cookie.
-              </para>
-              <para>
-              <see langword="null"/> if not present.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Discard">
-            <summary>
-            Gets a value indicating whether the client discards the cookie
-            unconditionally when the client terminates.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the client discards the cookie unconditionally
-              when the client terminates; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Domain">
-            <summary>
-            Gets or sets the value of the Domain attribute of the cookie.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the domain name that
-              the cookie is valid for.
-              </para>
-              <para>
-              An empty string if this attribute is not needed.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Expired">
-            <summary>
-            Gets or sets a value indicating whether the cookie has expired.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the cookie has expired; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Expires">
-            <summary>
-            Gets or sets the value of the Expires attribute of the cookie.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.DateTime"/> that represents the date and time that
-              the cookie expires on.
-              </para>
-              <para>
-              <see cref="F:System.DateTime.MinValue"/> if this attribute is not needed.
-              </para>
-              <para>
-              The default value is <see cref="F:System.DateTime.MinValue"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.HttpOnly">
-            <summary>
-            Gets or sets a value indicating whether non-HTTP APIs can access
-            the cookie.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if non-HTTP APIs cannot access the cookie; otherwise,
-              <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Name">
-            <summary>
-            Gets or sets the name of the cookie.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the name of the cookie.
-              </para>
-              <para>
-              The name must be a token defined in
-              <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
-              RFC 2616</see>.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentNullException">
-            The value specified for a set operation is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The value specified for a set operation is an empty string.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              The value specified for a set operation starts with a dollar sign.
-              </para>
-              <para>
-              - or -
-              </para>
-              <para>
-              The value specified for a set operation contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Path">
-            <summary>
-            Gets or sets the value of the Path attribute of the cookie.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the subset of URI on
-            the origin server that the cookie applies to.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Port">
-            <summary>
-            Gets the value of the Port attribute of the cookie.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the list of TCP ports
-              that the cookie applies to.
-              </para>
-              <para>
-              <see langword="null"/> if not present.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Secure">
-            <summary>
-            Gets or sets a value indicating whether the security level of
-            the cookie is secure.
-            </summary>
-            <remarks>
-            When this property is <c>true</c>, the cookie may be included in
-            the request only if the request is transmitted over HTTPS.
-            </remarks>
-            <value>
-              <para>
-              <c>true</c> if the security level of the cookie is secure;
-              otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.TimeStamp">
-            <summary>
-            Gets the time when the cookie was issued.
-            </summary>
-            <value>
-            A <see cref="T:System.DateTime"/> that represents the time when
-            the cookie was issued.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Value">
-            <summary>
-            Gets or sets the value of the cookie.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the value of the cookie.
-            </value>
-            <exception cref="T:System.ArgumentException">
-            The value specified for a set operation is a string not enclosed in
-            double quotes that contains an invalid character.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.Cookie.Version">
-            <summary>
-            Gets the value of the Version attribute of the cookie.
-            </summary>
-            <value>
-              <para>
-              An <see cref="T:System.Int32"/> that represents the version of HTTP state
-              management that the cookie conforms to.
-              </para>
-              <para>
-              0 or 1. 0 if not present.
-              </para>
-              <para>
-              The default value is 0.
-              </para>
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.ToResponseString">
-            <summary>
-            Returns a string that represents the current cookie instance.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that is suitable for the Set-Cookie response
-            header.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.Equals(System.Object)">
-            <summary>
-            Determines whether the current cookie instance is equal to
-            the specified <see cref="T:System.Object"/> instance.
-            </summary>
-            <param name="comparand">
-              <para>
-              An <see cref="T:System.Object"/> instance to compare with
-              the current cookie instance.
-              </para>
-              <para>
-              An reference to a <see cref="T:WebSocketSharp.Net.Cookie"/> instance.
-              </para>
-            </param>
-            <returns>
-            <c>true</c> if the current cookie instance is equal to
-            <paramref name="comparand"/>; otherwise, <c>false</c>.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.GetHashCode">
-            <summary>
-            Gets a hash code for the current cookie instance.
-            </summary>
-            <returns>
-            An <see cref="T:System.Int32"/> that represents the hash code.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.Cookie.ToString">
-            <summary>
-            Returns a string that represents the current cookie instance.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that is suitable for the Cookie request header.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.CookieCollection">
-            <summary>
-            Provides a collection of instances of the <see cref="T:WebSocketSharp.Net.Cookie"/> class.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.CookieCollection"/> class.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.CookieCollection.Count">
-            <summary>
-            Gets the number of cookies in the collection.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of cookies in
-            the collection.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.CookieCollection.IsReadOnly">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.CookieCollection.IsSynchronized">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.CookieCollection.Item(System.Int32)">
-            <summary>
-            Gets the cookie at the specified index from the collection.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.Cookie"/> at the specified index in the collection.
-            </value>
-            <param name="index">
-            An <see cref="T:System.Int32"/> that specifies the zero-based index of the cookie
-            to find.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="index"/> is out of allowable range for the collection.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.CookieCollection.Item(System.String)">
-            <summary>
-            Gets the cookie with the specified name from the collection.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Net.Cookie"/> with the specified name in the collection.
-              </para>
-              <para>
-              <see langword="null"/> if not found.
-              </para>
-            </value>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the cookie to find.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.CookieCollection.SyncRoot">
-            <summary>
-            Gets an object used to synchronize access to the collection.
-            </summary>
-            <value>
-            An <see cref="T:System.Object"/> used to synchronize access to the collection.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.Add(WebSocketSharp.Net.Cookie)">
-            <summary>
-            Adds the specified cookie to the collection.
-            </summary>
-            <param name="cookie">
-            A <see cref="T:WebSocketSharp.Net.Cookie"/> to add.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The collection is read-only.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookie"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.Add(WebSocketSharp.Net.CookieCollection)">
-            <summary>
-            Adds the specified cookies to the collection.
-            </summary>
-            <param name="cookies">
-            A <see cref="T:WebSocketSharp.Net.CookieCollection"/> that contains the cookies to add.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The collection is read-only.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookies"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.Clear">
-            <summary>
-            Removes all cookies from the collection.
-            </summary>
-            <exception cref="T:System.InvalidOperationException">
-            The collection is read-only.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.Contains(WebSocketSharp.Net.Cookie)">
-            <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="T:WebSocketSharp.Net.Cookie"/> to find.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookie"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.CopyTo(WebSocketSharp.Net.Cookie[],System.Int32)">
-            <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="T:WebSocketSharp.Net.Cookie"/> that specifies the destination of
-            the elements copied from the collection.
-            </param>
-            <param name="index">
-            An <see cref="T:System.Int32"/> that specifies the zero-based index in
-            the array at which copying starts.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="array"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="index"/> is less than zero.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            The space from <paramref name="index"/> to the end of
-            <paramref name="array"/> is not enough to copy to.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.GetEnumerator">
-            <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>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.Remove(WebSocketSharp.Net.Cookie)">
-            <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="T:WebSocketSharp.Net.Cookie"/> to remove.
-            </param>
-            <exception cref="T:System.InvalidOperationException">
-            The collection is read-only.
-            </exception>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookie"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieCollection.System#Collections#IEnumerable#GetEnumerator">
-            <summary>
-            Gets the enumerator that iterates through the collection.
-            </summary>
-            <returns>
-            An <see cref="T:System.Collections.IEnumerator"/> instance that can be used to iterate
-            through the collection.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.CookieException">
-            <summary>
-            The exception that is thrown when a <see cref="T:WebSocketSharp.Net.Cookie"/> gets an error.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.CookieException"/> class
-            with the serialized data.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the source for
-            the deserialization.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="serializationInfo"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieException.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.CookieException"/> class.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieException.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Populates the specified <see cref="T:System.Runtime.Serialization.SerializationInfo"/> instance with
-            the data needed to serialize the current instance.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the destination for
-            the serialization.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="serializationInfo"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.CookieException.System#Runtime#Serialization#ISerializable#GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Populates the specified <see cref="T:System.Runtime.Serialization.SerializationInfo"/> instance with
-            the data needed to serialize the current instance.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the destination for
-            the serialization.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="serializationInfo"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpListener">
-            <summary>
-            Provides a simple, programmatically controlled HTTP listener.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpListener"/> class.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.AuthenticationSchemes">
-            <summary>
-            Gets or sets the scheme used to authenticate the clients.
-            </summary>
-            <value>
-            One of the <see cref="T:WebSocketSharp.Net.AuthenticationSchemes"/> enum values,
-            represents the scheme used to authenticate the clients. The default value is
-            <see cref="F:WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.AuthenticationSchemeSelector">
-            <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="P:WebSocketSharp.Net.HttpListener.AuthenticationSchemes"/> property as the authentication
-            scheme for all requests.
-            </remarks>
-            <value>
-            A <c>Func&lt;<see cref="T:WebSocketSharp.Net.HttpListenerRequest"/>, <see cref="P:WebSocketSharp.Net.HttpListener.AuthenticationSchemes"/>&gt;</c>
-            delegate that references the method used to select an authentication scheme. The default
-            value is <see langword="null"/>.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.CertificateFolderPath">
-            <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="F:System.Environment.SpecialFolder.ApplicationData"/>)</c> is used as the default path.
-              </para>
-            </remarks>
-            <value>
-            A <see cref="T:System.String"/> that represents the path to the folder in which stores
-            the certificate files. The default value is <see langword="null"/>.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.IgnoreWriteExceptions">
-            <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="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.IsListening">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.IsSupported">
-            <summary>
-            Gets a value indicating whether the listener can be used with the current operating system.
-            </summary>
-            <value>
-            <c>true</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.Log">
-            <summary>
-            Gets the logging functions.
-            </summary>
-            <remarks>
-            The default logging level is <see cref="F:WebSocketSharp.LogLevel.Error"/>. If you would like to change it,
-            you should set the <c>Log.Level</c> property to any of the <see cref="T:WebSocketSharp.LogLevel"/> enum
-            values.
-            </remarks>
-            <value>
-            A <see cref="T:WebSocketSharp.Logger"/> that provides the logging functions.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.Prefixes">
-            <summary>
-            Gets the URI prefixes handled by the listener.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.HttpListenerPrefixCollection"/> that contains the URI prefixes.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.Realm">
-            <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="T:System.String"/> that represents the name of the realm. The default value is
-            <see langword="null"/>.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.SslConfiguration">
-            <summary>
-            Gets or sets the SSL configuration used to authenticate the server and
-            optionally the client for secure connection.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.ServerSslConfiguration"/> that represents the configuration used to
-            authenticate the server and optionally the client for secure connection.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.UnsafeConnectionNtlmAuthentication">
-            <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="T:System.NotSupportedException"/>.
-            </remarks>
-            <value>
-            <c>true</c> if the authentication information of first request is used;
-            otherwise, <c>false</c>.
-            </value>
-            <exception cref="T:System.NotSupportedException">
-            Any use of this property.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListener.UserCredentialsFinder">
-            <summary>
-            Gets or sets the delegate called to find the credentials for an identity used to
-            authenticate a client.
-            </summary>
-            <value>
-            A <c>Func&lt;<see cref="T:System.Security.Principal.IIdentity"/>, <see cref="T:WebSocketSharp.Net.NetworkCredential"/>&gt;</c> delegate
-            that references the method used to find the credentials. The default value is
-            <see langword="null"/>.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.Abort">
-            <summary>
-            Shuts down the listener immediately.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.BeginGetContext(System.AsyncCallback,System.Object)">
-            <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="T:System.IAsyncResult"/> that represents the status of the asynchronous operation.
-            </returns>
-            <param name="callback">
-            An <see cref="T:System.AsyncCallback"/> delegate that references the method to invoke when
-            the asynchronous operation completes.
-            </param>
-            <param name="state">
-            An <see cref="T:System.Object"/> that represents a user defined object to pass to
-            the <paramref name="callback"/> delegate.
-            </param>
-            <exception cref="T:System.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="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.Close">
-            <summary>
-            Shuts down the listener.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.EndGetContext(System.IAsyncResult)">
-            <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="T:WebSocketSharp.Net.HttpListenerContext"/> that represents a request.
-            </returns>
-            <param name="asyncResult">
-            An <see cref="T:System.IAsyncResult"/> obtained by calling the <c>BeginGetContext</c> method.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="asyncResult"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="asyncResult"/> wasn't obtained by calling the <c>BeginGetContext</c> method.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This method was already called for the specified <paramref name="asyncResult"/>.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.GetContext">
-            <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="T:WebSocketSharp.Net.HttpListenerContext"/> that represents a request.
-            </returns>
-            <exception cref="T:System.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="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.Start">
-            <summary>
-            Starts receiving incoming requests.
-            </summary>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.Stop">
-            <summary>
-            Stops receiving incoming requests.
-            </summary>
-            <exception cref="T:System.ObjectDisposedException">
-            This listener has been closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListener.System#IDisposable#Dispose">
-            <summary>
-            Releases all resources used by the listener.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpListenerContext">
-            <summary>
-            Provides the access to the HTTP request and response objects used by
-            the <see cref="T:WebSocketSharp.Net.HttpListener"/> class.
-            </summary>
-            <remarks>
-            This class cannot be inherited.
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerContext.Request">
-            <summary>
-            Gets the HTTP request object that represents a client request.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.HttpListenerRequest"/> that represents the client request.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerContext.Response">
-            <summary>
-            Gets the HTTP response object used to send a response to the client.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.HttpListenerResponse"/> that represents a response to
-            the client request.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerContext.User">
-            <summary>
-            Gets the client information (identity, authentication, and security roles).
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Security.Principal.IPrincipal"/> instance or <see langword="null"/> if not
-              authenticated.
-              </para>
-              <para>
-              The instance describes the client.
-              </para>
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerContext.AcceptWebSocket(System.String)">
-            <summary>
-            Accepts a WebSocket handshake request.
-            </summary>
-            <returns>
-            A <see cref="T:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext"/> that represents
-            the WebSocket handshake request.
-            </returns>
-            <param name="protocol">
-            A <see cref="T:System.String"/> that specifies the subprotocol supported on
-            the WebSocket connection.
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="protocol"/> is empty.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="protocol"/> contains an invalid character.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This method has already been called.
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpListenerException">
-            <summary>
-            The exception that is thrown when a <see cref="T:WebSocketSharp.Net.HttpListener"/> gets an error
-            processing an HTTP request.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpListenerException"/> class from
-            the specified <see cref="T:System.Runtime.Serialization.SerializationInfo"/> and <see cref="T:System.Runtime.Serialization.StreamingContext"/>.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that contains the serialized object data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the source for the deserialization.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerException.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpListenerException"/> class.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerException.#ctor(System.Int32)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpListenerException"/> class
-            with the specified <paramref name="errorCode"/>.
-            </summary>
-            <param name="errorCode">
-            An <see cref="T:System.Int32"/> that identifies the error.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerException.#ctor(System.Int32,System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpListenerException"/> class
-            with the specified <paramref name="errorCode"/> and <paramref name="message"/>.
-            </summary>
-            <param name="errorCode">
-            An <see cref="T:System.Int32"/> that identifies the error.
-            </param>
-            <param name="message">
-            A <see cref="T:System.String"/> that describes the error.
-            </param>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerException.ErrorCode">
-            <summary>
-            Gets the error code that identifies the error that occurred.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that identifies the error.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpListenerPrefixCollection">
-            <summary>
-            Provides a collection used to store the URI prefixes for a instance of
-            the <see cref="T:WebSocketSharp.Net.HttpListener"/> class.
-            </summary>
-            <remarks>
-            The <see cref="T:WebSocketSharp.Net.HttpListener"/> instance responds to the request which has
-            a requested URI that the prefixes most closely match.
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerPrefixCollection.Count">
-            <summary>
-            Gets the number of prefixes in the collection.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of prefixes.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerPrefixCollection.IsReadOnly">
-            <summary>
-            Gets a value indicating whether the access to the collection is
-            read-only.
-            </summary>
-            <value>
-            Always returns <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerPrefixCollection.IsSynchronized">
-            <summary>
-            Gets a value indicating whether the access to the collection is
-            synchronized.
-            </summary>
-            <value>
-            Always returns <c>false</c>.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.Add(System.String)">
-            <summary>
-            Adds the specified URI prefix to the collection.
-            </summary>
-            <param name="uriPrefix">
-              <para>
-              A <see cref="T:System.String"/> that specifies the URI prefix to add.
-              </para>
-              <para>
-              It must be a well-formed URI prefix with http or https scheme,
-              and must end with a '/'.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="uriPrefix"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="uriPrefix"/> is invalid.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            The <see cref="T:WebSocketSharp.Net.HttpListener"/> instance associated with this
-            collection is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.Clear">
-            <summary>
-            Removes all URI prefixes from the collection.
-            </summary>
-            <exception cref="T:System.ObjectDisposedException">
-            The <see cref="T:WebSocketSharp.Net.HttpListener"/> instance associated with this
-            collection is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.Contains(System.String)">
-            <summary>
-            Returns a value indicating whether the collection contains the
-            specified URI prefix.
-            </summary>
-            <returns>
-            <c>true</c> if the collection contains the URI prefix; otherwise,
-            <c>false</c>.
-            </returns>
-            <param name="uriPrefix">
-            A <see cref="T:System.String"/> that specifies the URI prefix to test.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="uriPrefix"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            The <see cref="T:WebSocketSharp.Net.HttpListener"/> instance associated with this
-            collection is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.CopyTo(System.String[],System.Int32)">
-            <summary>
-            Copies the contents of the collection to the specified array of string.
-            </summary>
-            <param name="array">
-            An array of <see cref="T:System.String"/> that specifies the destination of
-            the URI prefix strings copied from the collection.
-            </param>
-            <param name="offset">
-            An <see cref="T:System.Int32"/> that specifies the zero-based index in
-            the array at which copying begins.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="array"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="offset"/> is less than zero.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            The space from <paramref name="offset"/> to the end of
-            <paramref name="array"/> is not enough to copy to.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            The <see cref="T:WebSocketSharp.Net.HttpListener"/> instance associated with this
-            collection is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.GetEnumerator">
-            <summary>
-            Gets the enumerator that iterates through the collection.
-            </summary>
-            <returns>
-            An <see cref="T:System.Collections.Generic.IEnumerator{string}"/>
-            instance that can be used to iterate through the collection.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.Remove(System.String)">
-            <summary>
-            Removes the specified URI prefix from the collection.
-            </summary>
-            <returns>
-            <c>true</c> if the URI prefix is successfully removed; otherwise,
-            <c>false</c>.
-            </returns>
-            <param name="uriPrefix">
-            A <see cref="T:System.String"/> that specifies the URI prefix to remove.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="uriPrefix"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            The <see cref="T:WebSocketSharp.Net.HttpListener"/> instance associated with this
-            collection is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefixCollection.System#Collections#IEnumerable#GetEnumerator">
-            <summary>
-            Gets the enumerator that iterates through the collection.
-            </summary>
-            <returns>
-            An <see cref="T:System.Collections.IEnumerator"/> instance that can be used to iterate
-            through the collection.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpListenerRequest">
-            <summary>
-            Represents an incoming HTTP request to a <see cref="T:WebSocketSharp.Net.HttpListener"/>
-            instance.
-            </summary>
-            <remarks>
-            This class cannot be inherited.
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.AcceptTypes">
-            <summary>
-            Gets the media types that are acceptable for the client.
-            </summary>
-            <value>
-              <para>
-              An array of <see cref="T:System.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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.ClientCertificateError">
-            <summary>
-            Gets an error code that identifies a problem with the certificate
-            provided by the client.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents an error code.
-            </value>
-            <exception cref="T:System.NotSupportedException">
-            This property is not supported.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.ContentEncoding">
-            <summary>
-            Gets the encoding for the entity body data included in the request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Text.Encoding"/> converted from the charset value of the
-              Content-Type header.
-              </para>
-              <para>
-              <see cref="P:System.Text.Encoding.UTF8"/> if the charset value is not available.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.ContentLength64">
-            <summary>
-            Gets the length in bytes of the entity body data included in the
-            request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Int64"/> converted from the value of the Content-Length
-              header.
-              </para>
-              <para>
-              -1 if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.ContentType">
-            <summary>
-            Gets the media type of the entity body data included in the request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of the Content-Type
-              header.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.Cookies">
-            <summary>
-            Gets the cookies included in the request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Net.CookieCollection"/> that contains the cookies.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.HasEntityBody">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.Headers">
-            <summary>
-            Gets the headers included in the request.
-            </summary>
-            <value>
-            A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the headers.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.HttpMethod">
-            <summary>
-            Gets the HTTP method specified by the client.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the HTTP method specified in
-            the request line.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.InputStream">
-            <summary>
-            Gets a stream that contains the entity body data included in
-            the request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.IO.Stream"/> that contains the entity body data.
-              </para>
-              <para>
-              <see cref="F:System.IO.Stream.Null"/> if the entity body data is not available.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.IsAuthenticated">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.IsLocal">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.IsSecureConnection">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.IsWebSocketRequest">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.KeepAlive">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.LocalEndPoint">
-            <summary>
-            Gets the endpoint to which the request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the server IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.ProtocolVersion">
-            <summary>
-            Gets the HTTP version specified by the client.
-            </summary>
-            <value>
-            A <see cref="T:System.Version"/> that represents the HTTP version specified in
-            the request line.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.QueryString">
-            <summary>
-            Gets the query string included in the request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the query
-              parameters.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.RawUrl">
-            <summary>
-            Gets the raw URL specified by the client.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the request target specified in
-            the request line.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.RemoteEndPoint">
-            <summary>
-            Gets the endpoint from which the request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the client IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.RequestTraceIdentifier">
-            <summary>
-            Gets the trace identifier of the request.
-            </summary>
-            <value>
-            A <see cref="T:System.Guid"/> that represents the trace identifier.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.Url">
-            <summary>
-            Gets the URL requested by the client.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Uri"/> that represents the URL parsed from the request.
-              </para>
-              <para>
-              <see langword="null"/> if the URL cannot be parsed.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.UrlReferrer">
-            <summary>
-            Gets the URI of the resource from which the requested URL was obtained.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Uri"/> converted from the value of the Referer header.
-              </para>
-              <para>
-              <see langword="null"/> if the header value is not available.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.UserAgent">
-            <summary>
-            Gets the user agent from which the request is originated.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of the User-Agent
-              header.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.UserHostAddress">
-            <summary>
-            Gets the IP address and port number to which the request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the server IP address and port
-            number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.UserHostName">
-            <summary>
-            Gets the server host name requested by the client.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.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>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerRequest.UserLanguages">
-            <summary>
-            Gets the natural languages that are acceptable for the client.
-            </summary>
-            <value>
-              <para>
-              An array of <see cref="T:System.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>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerRequest.BeginGetClientCertificate(System.AsyncCallback,System.Object)">
-            <summary>
-            Begins getting the certificate provided by the client asynchronously.
-            </summary>
-            <returns>
-            An <see cref="T:System.IAsyncResult"/> instance that indicates the status of the
-            operation.
-            </returns>
-            <param name="requestCallback">
-            An <see cref="T:System.AsyncCallback"/> delegate that invokes the method called
-            when the operation is complete.
-            </param>
-            <param name="state">
-            An <see cref="T:System.Object"/> that represents a user defined object to pass to
-            the callback delegate.
-            </param>
-            <exception cref="T:System.NotSupportedException">
-            This method is not supported.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerRequest.EndGetClientCertificate(System.IAsyncResult)">
-            <summary>
-            Ends an asynchronous operation to get the certificate provided by the
-            client.
-            </summary>
-            <returns>
-            A <see cref="T:System.Security.Cryptography.X509Certificates.X509Certificate2"/> that represents an X.509 certificate
-            provided by the client.
-            </returns>
-            <param name="asyncResult">
-            An <see cref="T:System.IAsyncResult"/> instance returned when the operation
-            started.
-            </param>
-            <exception cref="T:System.NotSupportedException">
-            This method is not supported.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerRequest.GetClientCertificate">
-            <summary>
-            Gets the certificate provided by the client.
-            </summary>
-            <returns>
-            A <see cref="T:System.Security.Cryptography.X509Certificates.X509Certificate2"/> that represents an X.509 certificate
-            provided by the client.
-            </returns>
-            <exception cref="T:System.NotSupportedException">
-            This method is not supported.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerRequest.ToString">
-            <summary>
-            Returns a string that represents the current instance.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that contains the request line and headers
-            included in the request.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpListenerResponse">
-            <summary>
-            Represents an HTTP response to an HTTP request received by
-            a <see cref="T:WebSocketSharp.Net.HttpListener"/> instance.
-            </summary>
-            <remarks>
-            This class cannot be inherited.
-            </remarks>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.ContentEncoding">
-            <summary>
-            Gets or sets the encoding for the entity body data included in
-            the response.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Text.Encoding"/> that represents the encoding for
-              the entity body data.
-              </para>
-              <para>
-              <see langword="null"/> if no encoding is specified.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.ContentLength64">
-            <summary>
-            Gets or sets the number of bytes in the entity body data included in
-            the response.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Int64"/> that represents the number of bytes in
-              the entity body data.
-              </para>
-              <para>
-              It is used for the value of the Content-Length header.
-              </para>
-              <para>
-              The default value is zero.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The value specified for a set operation is less than zero.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.ContentType">
-            <summary>
-            Gets or sets the media type of the entity body included in
-            the response.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the media type of
-              the entity body.
-              </para>
-              <para>
-              It is used for the value of the Content-Type header.
-              </para>
-              <para>
-              <see langword="null"/> if no media type is specified.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The value specified for a set operation is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value specified for a set operation contains
-              an invalid character.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.Cookies">
-            <summary>
-            Gets or sets the collection of cookies sent with the response.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.CookieCollection"/> that contains the cookies sent with
-            the response.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.Headers">
-            <summary>
-            Gets or sets the collection of the HTTP headers sent to the client.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.WebHeaderCollection"/> that contains the headers sent to
-            the client.
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The value specified for a set operation is not valid for a response.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.KeepAlive">
-            <summary>
-            Gets or sets a value indicating whether the server requests
-            a persistent connection.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the server requests a persistent connection;
-              otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>true</c>.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.OutputStream">
-            <summary>
-            Gets a stream instance to which the entity body data can be written.
-            </summary>
-            <value>
-            A <see cref="T:System.IO.Stream"/> instance to which the entity body data can be
-            written.
-            </value>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.ProtocolVersion">
-            <summary>
-            Gets or sets the HTTP version used for the response.
-            </summary>
-            <value>
-            A <see cref="T:System.Version"/> that represents the HTTP version used for
-            the response.
-            </value>
-            <exception cref="T:System.ArgumentNullException">
-            The value specified for a set operation is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The value specified for a set operation does not have its Major
-              property set to 1.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value specified for a set operation does not have its Minor
-              property set to either 0 or 1.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.RedirectLocation">
-            <summary>
-            Gets or sets the URL to which the client is redirected to locate
-            a requested resource.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the absolute URL for
-              the redirect location.
-              </para>
-              <para>
-              It is used for the value of the Location header.
-              </para>
-              <para>
-              <see langword="null"/> if no redirect location is specified.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              The value specified for a set operation is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value specified for a set operation is not an absolute URL.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.SendChunked">
-            <summary>
-            Gets or sets a value indicating whether the response uses the chunked
-            transfer encoding.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the response uses the chunked transfer encoding;
-              otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.StatusCode">
-            <summary>
-            Gets or sets the HTTP status code returned to the client.
-            </summary>
-            <value>
-              <para>
-              An <see cref="T:System.Int32"/> that represents the HTTP status code for
-              the response to the request.
-              </para>
-              <para>
-              The default value is 200. It indicates that the request has
-              succeeded.
-              </para>
-            </value>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-            <exception cref="T:System.Net.ProtocolViolationException">
-              <para>
-              The value specified for a set operation is invalid.
-              </para>
-              <para>
-              Valid values are between 100 and 999 inclusive.
-              </para>
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpListenerResponse.StatusDescription">
-            <summary>
-            Gets or sets the description of the HTTP status code returned to
-            the client.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the description of
-              the HTTP status code for the response to the request.
-              </para>
-              <para>
-              The default value is
-              the <see href="http://tools.ietf.org/html/rfc2616#section-10">
-              RFC 2616</see> description for the <see cref="P:WebSocketSharp.Net.HttpListenerResponse.StatusCode"/>
-              property value.
-              </para>
-              <para>
-              An empty string if an RFC 2616 description does not exist.
-              </para>
-            </value>
-            <exception cref="T:System.ArgumentNullException">
-            The value specified for a set operation is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            The value specified for a set operation contains an invalid character.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.Abort">
-            <summary>
-            Closes the connection to the client without sending a response.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.AppendCookie(WebSocketSharp.Net.Cookie)">
-            <summary>
-            Appends the specified cookie to the cookies sent with the response.
-            </summary>
-            <param name="cookie">
-            A <see cref="T:WebSocketSharp.Net.Cookie"/> to append.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookie"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.AppendHeader(System.String,System.String)">
-            <summary>
-            Appends an HTTP header with the specified name and value to
-            the headers for the response.
-            </summary>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to
-            append.
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the header to
-            append.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a restricted header name.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The current headers do not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.Close">
-            <summary>
-            Sends the response to the client and releases the resources used by
-            this instance.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.Close(System.Byte[],System.Boolean)">
-            <summary>
-            Sends the response with the specified entity body data to the client
-            and releases the resources used by this instance.
-            </summary>
-            <param name="responseEntity">
-            An array of <see cref="T:System.Byte"/> that contains the entity body data.
-            </param>
-            <param name="willBlock">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if this method blocks execution while
-            flushing the stream to the client; otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="responseEntity"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.CopyFrom(WebSocketSharp.Net.HttpListenerResponse)">
-            <summary>
-            Copies some properties from the specified response instance to
-            this instance.
-            </summary>
-            <param name="templateResponse">
-            A <see cref="T:WebSocketSharp.Net.HttpListenerResponse"/> to copy.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="templateResponse"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.Redirect(System.String)">
-            <summary>
-            Configures the response to redirect the client's request to
-            the specified URL.
-            </summary>
-            <remarks>
-            This method sets the <see cref="P:WebSocketSharp.Net.HttpListenerResponse.RedirectLocation"/> property to
-            <paramref name="url"/>, the <see cref="P:WebSocketSharp.Net.HttpListenerResponse.StatusCode"/> property to
-            302, and the <see cref="P:WebSocketSharp.Net.HttpListenerResponse.StatusDescription"/> property to "Found".
-            </remarks>
-            <param name="url">
-            A <see cref="T:System.String"/> that specifies the absolute URL to which
-            the client is redirected to locate a requested resource.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="url"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="url"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="url"/> is not an absolute URL.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The response is already being sent.
-            </exception>
-            <exception cref="T:System.ObjectDisposedException">
-            This instance is closed.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.SetCookie(WebSocketSharp.Net.Cookie)">
-            <summary>
-            Adds or updates a cookie in the cookies sent with the response.
-            </summary>
-            <param name="cookie">
-            A <see cref="T:WebSocketSharp.Net.Cookie"/> to set.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="cookie"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="cookie"/> already exists in the cookies but
-            it cannot be updated.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.SetHeader(System.String,System.String)">
-            <summary>
-            Adds or updates an HTTP header with the specified name and value in
-            the headers for the response.
-            </summary>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to set.
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the header to set.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a restricted header name.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            The current headers do not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerResponse.System#IDisposable#Dispose">
-            <summary>
-            Releases all resources used by this instance.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpUtility.htmlEncode(System.String,System.Boolean)">
-            <summary>
-            Converts the specified string to an HTML-encoded string.
-            </summary>
-            <remarks>
-              <para>
-              This method starts encoding with a NCR from the character code 160
-              but does not stop at the character code 255.
-              </para>
-              <para>
-              One reason is the unicode characters &#65308; and &#65310; that
-              look like &lt; and &gt;.
-              </para>
-            </remarks>
-            <returns>
-            A <see cref="T:System.String"/> that represents an encoded string.
-            </returns>
-            <param name="s">
-            A <see cref="T:System.String"/> to encode.
-            </param>
-            <param name="minimal">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if encodes without a NCR;
-            otherwise, <c>false</c>.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpUtility.initEntities">
-            <summary>
-            Initializes the _entities field.
-            </summary>
-            <remarks>
-            This method builds a dictionary of HTML character entity references.
-            This dictionary comes from the HTML 4.01 W3C recommendation.
-            </remarks>
-        </member>
-        <member name="T:WebSocketSharp.Net.WebHeaderCollection">
-            <summary>
-            Provides a collection of the HTTP headers associated with a request or
-            response.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.WebHeaderCollection"/> class
-            from the specified instances of the <see cref="T:System.Runtime.Serialization.SerializationInfo"/> and
-            <see cref="T:System.Runtime.Serialization.StreamingContext"/> classes.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that contains the serialized
-            object data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the source for
-            the deserialization.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="serializationInfo"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            An element with the specified name is not found in
-            <paramref name="serializationInfo"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.WebHeaderCollection"/>
-            class.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebHeaderCollection.AllKeys">
-            <summary>
-            Gets all header names in the collection.
-            </summary>
-            <value>
-            An array of <see cref="T:System.String"/> that contains all header names in
-            the collection.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebHeaderCollection.Count">
-            <summary>
-            Gets the number of headers in the collection.
-            </summary>
-            <value>
-            An <see cref="T:System.Int32"/> that represents the number of headers in
-            the collection.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebHeaderCollection.Item(WebSocketSharp.Net.HttpRequestHeader)">
-            <summary>
-            Gets or sets the specified request header.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the value of the request header.
-            </value>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpRequestHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the request header to get or set.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the request header.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebHeaderCollection.Item(WebSocketSharp.Net.HttpResponseHeader)">
-            <summary>
-            Gets or sets the specified response header.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the value of the response header.
-            </value>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpResponseHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the response header to get or set.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the response header.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebHeaderCollection.Keys">
-            <summary>
-            Gets a collection of header names in the collection.
-            </summary>
-            <value>
-            A <see cref="T:System.Collections.Specialized.NameObjectCollectionBase.KeysCollection"/> that contains
-            all header names in the collection.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.AddWithoutValidate(System.String,System.String)">
-            <summary>
-            Adds a header to the collection without checking if the header is on
-            the restricted header list.
-            </summary>
-            <param name="headerName">
-            A <see cref="T:System.String"/> that specifies the name of the header to add.
-            </param>
-            <param name="headerValue">
-            A <see cref="T:System.String"/> that specifies the value of the header to add.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="headerName"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="headerName"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerName"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerName"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerValue"/> contains an invalid character.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="headerValue"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Add(System.String)">
-            <summary>
-            Adds the specified header to the collection.
-            </summary>
-            <param name="header">
-            A <see cref="T:System.String"/> that specifies the header to add,
-            with the name and value separated by a colon character (':').
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="header"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="header"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="header"/> does not contain a colon character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The name part of <paramref name="header"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The name part of <paramref name="header"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The name part of <paramref name="header"/> contains an invalid
-              character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              The value part of <paramref name="header"/> contains an invalid
-              character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of the value part of <paramref name="header"/> is greater
-            than 65,535 characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Add(WebSocketSharp.Net.HttpRequestHeader,System.String)">
-            <summary>
-            Adds the specified request header with the specified value to
-            the collection.
-            </summary>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpRequestHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the request header to add.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the header to add.
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the request header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Add(WebSocketSharp.Net.HttpResponseHeader,System.String)">
-            <summary>
-            Adds the specified response header with the specified value to
-            the collection.
-            </summary>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpResponseHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the response header to add.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the header to add.
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the response header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Add(System.String,System.String)">
-            <summary>
-            Adds a header with the specified name and value to the collection.
-            </summary>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to add.
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the header to add.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a restricted header name.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Clear">
-            <summary>
-            Removes all headers from the collection.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Get(System.Int32)">
-            <summary>
-            Get the value of the header at the specified index in the collection.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that receives the value of the header.
-            </returns>
-            <param name="index">
-            An <see cref="T:System.Int32"/> that specifies the zero-based index of the header
-            to find.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="index"/> is out of allowable range of indexes for
-            the collection.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Get(System.String)">
-            <summary>
-            Get the value of the header with the specified name in the collection.
-            </summary>
-            <returns>
-              <para>
-              A <see cref="T:System.String"/> that receives the value of the header.
-              </para>
-              <para>
-              <see langword="null"/> if not found.
-              </para>
-            </returns>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to find.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.GetEnumerator">
-            <summary>
-            Gets the enumerator used to iterate through the collection.
-            </summary>
-            <returns>
-            An <see cref="T:System.Collections.IEnumerator"/> instance used to iterate through
-            the collection.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.GetKey(System.Int32)">
-            <summary>
-            Get the name of the header at the specified index in the collection.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that receives the name of the header.
-            </returns>
-            <param name="index">
-            An <see cref="T:System.Int32"/> that specifies the zero-based index of the header
-            to find.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="index"/> is out of allowable range of indexes for
-            the collection.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.GetValues(System.Int32)">
-            <summary>
-            Get the values of the header at the specified index in the collection.
-            </summary>
-            <returns>
-              <para>
-              An array of <see cref="T:System.String"/> that receives the values of
-              the header.
-              </para>
-              <para>
-              <see langword="null"/> if not present.
-              </para>
-            </returns>
-            <param name="index">
-            An <see cref="T:System.Int32"/> that specifies the zero-based index of the header
-            to find.
-            </param>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            <paramref name="index"/> is out of allowable range of indexes for
-            the collection.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.GetValues(System.String)">
-            <summary>
-            Get the values of the header with the specified name in the collection.
-            </summary>
-            <returns>
-              <para>
-              An array of <see cref="T:System.String"/> that receives the values of
-              the header.
-              </para>
-              <para>
-              <see langword="null"/> if not present.
-              </para>
-            </returns>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to find.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> instance with the data
-            needed to serialize this instance.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with the data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the destination for
-            the serialization.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="serializationInfo"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.IsRestricted(System.String)">
-            <summary>
-            Determines whether the specified HTTP header can be set for the request.
-            </summary>
-            <returns>
-            <c>true</c> if the header cannot be set; otherwise, <c>false</c>.
-            </returns>
-            <param name="headerName">
-            A <see cref="T:System.String"/> that specifies the name of the header to test.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="headerName"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="headerName"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerName"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerName"/> contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.IsRestricted(System.String,System.Boolean)">
-            <summary>
-            Determines whether the specified HTTP header can be set for the request
-            or the response.
-            </summary>
-            <returns>
-            <c>true</c> if the header cannot be set; otherwise, <c>false</c>.
-            </returns>
-            <param name="headerName">
-            A <see cref="T:System.String"/> that specifies the name of the header to test.
-            </param>
-            <param name="response">
-            A <see cref="T:System.Boolean"/>: <c>true</c> if the test is for the response;
-            otherwise, <c>false</c>.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="headerName"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="headerName"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerName"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="headerName"/> contains an invalid character.
-              </para>
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.OnDeserialization(System.Object)">
-            <summary>
-            Implements the <see cref="T:System.Runtime.Serialization.ISerializable"/> interface and raises
-            the deserialization event when the deserialization is complete.
-            </summary>
-            <param name="sender">
-            An <see cref="T:System.Object"/> instance that represents the source of
-            the deserialization event.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Remove(WebSocketSharp.Net.HttpRequestHeader)">
-            <summary>
-            Removes the specified request header from the collection.
-            </summary>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpRequestHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the request header to remove.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="header"/> is a restricted header.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the request header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Remove(WebSocketSharp.Net.HttpResponseHeader)">
-            <summary>
-            Removes the specified response header from the collection.
-            </summary>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpResponseHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the response header to remove.
-              </para>
-            </param>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="header"/> is a restricted header.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the response header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Remove(System.String)">
-            <summary>
-            Removes the specified header from the collection.
-            </summary>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to remove.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a restricted header name.
-              </para>
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Set(WebSocketSharp.Net.HttpRequestHeader,System.String)">
-            <summary>
-            Sets the specified request header to the specified value.
-            </summary>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpRequestHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the request header to set.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the request header
-            to set.
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the request header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Set(WebSocketSharp.Net.HttpResponseHeader,System.String)">
-            <summary>
-            Sets the specified response header to the specified value.
-            </summary>
-            <param name="header">
-              <para>
-              One of the <see cref="T:WebSocketSharp.Net.HttpResponseHeader"/> enum values.
-              </para>
-              <para>
-              It specifies the response header to set.
-              </para>
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the response header
-            to set.
-            </param>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="header"/> is a restricted header.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the response header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.Set(System.String,System.String)">
-            <summary>
-            Sets the specified header to the specified value.
-            </summary>
-            <param name="name">
-            A <see cref="T:System.String"/> that specifies the name of the header to set.
-            </param>
-            <param name="value">
-            A <see cref="T:System.String"/> that specifies the value of the header to set.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="name"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-              <para>
-              <paramref name="name"/> is an empty string.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a string of spaces.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="value"/> contains an invalid character.
-              </para>
-              <para>
-              -or-
-              </para>
-              <para>
-              <paramref name="name"/> is a restricted header name.
-              </para>
-            </exception>
-            <exception cref="T:System.ArgumentOutOfRangeException">
-            The length of <paramref name="value"/> is greater than 65,535
-            characters.
-            </exception>
-            <exception cref="T:System.InvalidOperationException">
-            This instance does not allow the header.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.ToByteArray">
-            <summary>
-            Converts the current instance to an array of byte.
-            </summary>
-            <returns>
-            An array of <see cref="T:System.Byte"/> converted from a string that represents
-            the current instance.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.ToString">
-            <summary>
-            Returns a string that represents the current instance.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that represents all headers in the collection.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebHeaderCollection.System#Runtime#Serialization#ISerializable#GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
-            <summary>
-            Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> instance with the data
-            needed to serialize this instance.
-            </summary>
-            <param name="serializationInfo">
-            A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with the data.
-            </param>
-            <param name="streamingContext">
-            A <see cref="T:System.Runtime.Serialization.StreamingContext"/> that specifies the destination for
-            the serialization.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="serializationInfo"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpVersion">
-            <summary>
-            Provides the HTTP version numbers.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpVersion.Version10">
-            <summary>
-            Provides a <see cref="T:System.Version"/> instance for the HTTP/1.0.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpVersion.Version11">
-            <summary>
-            Provides a <see cref="T:System.Version"/> instance for the HTTP/1.1.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpVersion.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpVersion"/> class.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpStatusCode">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Continue">
-            <summary>
-            Equivalent to status code 100. Indicates that the client should continue
-            with its request.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.SwitchingProtocols">
-            <summary>
-            Equivalent to status code 101. Indicates that the server is switching
-            the HTTP version or protocol on the connection.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.OK">
-            <summary>
-            Equivalent to status code 200. Indicates that the client's request has
-            succeeded.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Created">
-            <summary>
-            Equivalent to status code 201. Indicates that the client's request has
-            been fulfilled and resulted in a new resource being created.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Accepted">
-            <summary>
-            Equivalent to status code 202. Indicates that the client's request has
-            been accepted for processing, but the processing has not been completed.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.NonAuthoritativeInformation">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.NoContent">
-            <summary>
-            Equivalent to status code 204. Indicates that the server has fulfilled
-            the client's request but does not need to return an entity-body.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.ResetContent">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.PartialContent">
-            <summary>
-            Equivalent to status code 206. Indicates that the server has fulfilled
-            the partial GET request for the resource.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.MultipleChoices">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Ambiguous">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.MovedPermanently">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Moved">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Found">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Redirect">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.SeeOther">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.RedirectMethod">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.NotModified">
-            <summary>
-            Equivalent to status code 304. Indicates that the client has performed
-            a conditional GET request and access is allowed, but the document has
-            not been modified.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.UseProxy">
-            <summary>
-            Equivalent to status code 305. Indicates that the requested resource
-            must be accessed through the proxy given by the Location field.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Unused">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.TemporaryRedirect">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.RedirectKeepVerb">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.BadRequest">
-            <summary>
-            Equivalent to status code 400. Indicates that the client's request could
-            not be understood by the server due to malformed syntax.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Unauthorized">
-            <summary>
-            Equivalent to status code 401. Indicates that the client's request
-            requires user authentication.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.PaymentRequired">
-            <summary>
-            Equivalent to status code 402. This status code is reserved for future
-            use.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Forbidden">
-            <summary>
-            Equivalent to status code 403. Indicates that the server understood
-            the client's request but is refusing to fulfill it.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.NotFound">
-            <summary>
-            Equivalent to status code 404. Indicates that the server has not found
-            anything matching the request URI.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.MethodNotAllowed">
-            <summary>
-            Equivalent to status code 405. Indicates that the method specified
-            in the request line is not allowed for the resource identified by
-            the request URI.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.NotAcceptable">
-            <summary>
-            Equivalent to status code 406. Indicates that the server does not
-            have the appropriate resource to respond to the Accept headers in
-            the client's request.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.ProxyAuthenticationRequired">
-            <summary>
-            Equivalent to status code 407. Indicates that the client must first
-            authenticate itself with the proxy.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.RequestTimeout">
-            <summary>
-            Equivalent to status code 408. Indicates that the client did not produce
-            a request within the time that the server was prepared to wait.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Conflict">
-            <summary>
-            Equivalent to status code 409. Indicates that the client's request could
-            not be completed due to a conflict on the server.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.Gone">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.LengthRequired">
-            <summary>
-            Equivalent to status code 411. Indicates that the server refuses to
-            accept the client's request without a defined Content-Length.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.PreconditionFailed">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.RequestEntityTooLarge">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.RequestUriTooLong">
-            <summary>
-            Equivalent to status code 414. Indicates that the request URI is longer
-            than the server is willing to interpret.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.UnsupportedMediaType">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.RequestedRangeNotSatisfiable">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.ExpectationFailed">
-            <summary>
-            Equivalent to status code 417. Indicates that the expectation given in
-            an Expect request header could not be met by the server.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.InternalServerError">
-            <summary>
-            Equivalent to status code 500. Indicates that the server encountered
-            an unexpected condition which prevented it from fulfilling the client's
-            request.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.NotImplemented">
-            <summary>
-            Equivalent to status code 501. Indicates that the server does not
-            support the functionality required to fulfill the client's request.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.BadGateway">
-            <summary>
-            Equivalent to status code 502. Indicates that a gateway or proxy server
-            received an invalid response from the upstream server.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.ServiceUnavailable">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.GatewayTimeout">
-            <summary>
-            Equivalent to status code 504. Indicates that a gateway or proxy server
-            did not receive a timely response from the upstream server or some other
-            auxiliary server.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpStatusCode.HttpVersionNotSupported">
-            <summary>
-            Equivalent to status code 505. Indicates that the server does not
-            support the HTTP version used in the client's request.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext">
-            <summary>
-            Provides the access to the information in a WebSocket handshake request to
-            a <see cref="T:WebSocketSharp.Net.HttpListener"/> instance.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.CookieCollection">
-            <summary>
-            Gets the HTTP cookies included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Net.CookieCollection"/> that contains
-              the cookies.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.Headers">
-            <summary>
-            Gets the HTTP headers included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the headers.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.Host">
-            <summary>
-            Gets the value of the Host header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the server host name requested
-              by the client.
-              </para>
-              <para>
-              It includes the port number if provided.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.IsAuthenticated">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.IsLocal">
-            <summary>
-            Gets a value indicating whether the handshake request is sent from
-            the local computer.
-            </summary>
-            <value>
-            <c>true</c> if the handshake request is sent from the same computer
-            as the server; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.IsSecureConnection">
-            <summary>
-            Gets a value indicating whether a secure connection is used to send
-            the handshake request.
-            </summary>
-            <value>
-            <c>true</c> if the connection is secure; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.IsWebSocketRequest">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.Origin">
-            <summary>
-            Gets the value of the Origin header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of the Origin header.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.QueryString">
-            <summary>
-            Gets the query string included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the query
-              parameters.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.RequestUri">
-            <summary>
-            Gets the URI requested by the client.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Uri"/> that represents the URI parsed from the request.
-              </para>
-              <para>
-              <see langword="null"/> if the URI cannot be parsed.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.SecWebSocketKey">
-            <summary>
-            Gets the value of the Sec-WebSocket-Key header included in
-            the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of
-              the Sec-WebSocket-Key header.
-              </para>
-              <para>
-              The value is used to prove that the server received
-              a valid WebSocket handshake request.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.SecWebSocketProtocols">
-            <summary>
-            Gets the names of the subprotocols from the Sec-WebSocket-Protocol
-            header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              An <see cref="T:System.Collections.Generic.IEnumerable{string}"/>
-              instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the names of the subprotocols.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.SecWebSocketVersion">
-            <summary>
-            Gets the value of the Sec-WebSocket-Version header included in
-            the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the WebSocket protocol
-              version specified by the client.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.ServerEndPoint">
-            <summary>
-            Gets the endpoint to which the handshake request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the server IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.User">
-            <summary>
-            Gets the client information.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Security.Principal.IPrincipal"/> instance that represents identity,
-              authentication, and security roles for the client.
-              </para>
-              <para>
-              <see langword="null"/> if the client is not authenticated.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.UserEndPoint">
-            <summary>
-            Gets the endpoint from which the handshake request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the client IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.WebSocket">
-            <summary>
-            Gets the WebSocket instance used for two-way communication between
-            the client and server.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.WebSocket"/>.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebSockets.HttpListenerWebSocketContext.ToString">
-            <summary>
-            Returns a string that represents the current instance.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that contains the request line and headers
-            included in the handshake request.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext">
-            <summary>
-            Provides the access to the information in a WebSocket handshake request to
-            a <see cref="T:System.Net.Sockets.TcpListener"/> instance.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.CookieCollection">
-            <summary>
-            Gets the HTTP cookies included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:WebSocketSharp.Net.CookieCollection"/> that contains
-              the cookies.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.Headers">
-            <summary>
-            Gets the HTTP headers included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the headers.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.Host">
-            <summary>
-            Gets the value of the Host header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the server host name requested
-              by the client.
-              </para>
-              <para>
-              It includes the port number if provided.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.IsAuthenticated">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.IsLocal">
-            <summary>
-            Gets a value indicating whether the handshake request is sent from
-            the local computer.
-            </summary>
-            <value>
-            <c>true</c> if the handshake request is sent from the same computer
-            as the server; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.IsSecureConnection">
-            <summary>
-            Gets a value indicating whether a secure connection is used to send
-            the handshake request.
-            </summary>
-            <value>
-            <c>true</c> if the connection is secure; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.IsWebSocketRequest">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.Origin">
-            <summary>
-            Gets the value of the Origin header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of the Origin header.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.QueryString">
-            <summary>
-            Gets the query string included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the query
-              parameters.
-              </para>
-              <para>
-              An empty collection if not included.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.RequestUri">
-            <summary>
-            Gets the URI requested by the client.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Uri"/> that represents the URI parsed from the request.
-              </para>
-              <para>
-              <see langword="null"/> if the URI cannot be parsed.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.SecWebSocketKey">
-            <summary>
-            Gets the value of the Sec-WebSocket-Key header included in
-            the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of
-              the Sec-WebSocket-Key header.
-              </para>
-              <para>
-              The value is used to prove that the server received
-              a valid WebSocket handshake request.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.SecWebSocketProtocols">
-            <summary>
-            Gets the names of the subprotocols from the Sec-WebSocket-Protocol
-            header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              An <see cref="T:System.Collections.Generic.IEnumerable{string}"/>
-              instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the names of the subprotocols.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.SecWebSocketVersion">
-            <summary>
-            Gets the value of the Sec-WebSocket-Version header included in
-            the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the WebSocket protocol
-              version specified by the client.
-              </para>
-              <para>
-              <see langword="null"/> if the header is not present.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.ServerEndPoint">
-            <summary>
-            Gets the endpoint to which the handshake request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the server IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.User">
-            <summary>
-            Gets the client information.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Security.Principal.IPrincipal"/> instance that represents identity,
-              authentication, and security roles for the client.
-              </para>
-              <para>
-              <see langword="null"/> if the client is not authenticated.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.UserEndPoint">
-            <summary>
-            Gets the endpoint from which the handshake request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the client IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.WebSocket">
-            <summary>
-            Gets the WebSocket instance used for two-way communication between
-            the client and server.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.WebSocket"/>.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.ToString">
-            <summary>
-            Returns a string that represents the current instance.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that contains the request line and headers
-            included in the handshake request.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.WebSockets.WebSocketContext">
-            <summary>
-            Exposes the access to the information in a WebSocket handshake request.
-            </summary>
-            <remarks>
-            This class is an abstract class.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Net.WebSockets.WebSocketContext.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.WebSockets.WebSocketContext"/> class.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.CookieCollection">
-            <summary>
-            Gets the HTTP cookies included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.Net.CookieCollection"/> that contains
-            the cookies.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.Headers">
-            <summary>
-            Gets the HTTP headers included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the headers.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.Host">
-            <summary>
-            Gets the value of the Host header included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the server host name requested
-            by the client.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.IsAuthenticated">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.IsLocal">
-            <summary>
-            Gets a value indicating whether the handshake request is sent from
-            the local computer.
-            </summary>
-            <value>
-            <c>true</c> if the handshake request is sent from the same computer
-            as the server; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.IsSecureConnection">
-            <summary>
-            Gets a value indicating whether a secure connection is used to send
-            the handshake request.
-            </summary>
-            <value>
-            <c>true</c> if the connection is secure; otherwise, <c>false</c>.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.IsWebSocketRequest">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.Origin">
-            <summary>
-            Gets the value of the Origin header included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the value of the Origin header.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.QueryString">
-            <summary>
-            Gets the query string included in the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.Collections.Specialized.NameValueCollection"/> that contains the query parameters.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.RequestUri">
-            <summary>
-            Gets the URI requested by the client.
-            </summary>
-            <value>
-            A <see cref="T:System.Uri"/> that represents the URI parsed from the request.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.SecWebSocketKey">
-            <summary>
-            Gets the value of the Sec-WebSocket-Key header included in
-            the handshake request.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.String"/> that represents the value of
-              the Sec-WebSocket-Key header.
-              </para>
-              <para>
-              The value is used to prove that the server received
-              a valid WebSocket handshake request.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.SecWebSocketProtocols">
-            <summary>
-            Gets the names of the subprotocols from the Sec-WebSocket-Protocol
-            header included in the handshake request.
-            </summary>
-            <value>
-              <para>
-              An <see cref="T:System.Collections.Generic.IEnumerable{string}"/>
-              instance.
-              </para>
-              <para>
-              It provides an enumerator which supports the iteration over
-              the collection of the names of the subprotocols.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.SecWebSocketVersion">
-            <summary>
-            Gets the value of the Sec-WebSocket-Version header included in
-            the handshake request.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the WebSocket protocol
-            version specified by the client.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.ServerEndPoint">
-            <summary>
-            Gets the endpoint to which the handshake request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the server IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.User">
-            <summary>
-            Gets the client information.
-            </summary>
-            <value>
-            A <see cref="T:System.Security.Principal.IPrincipal"/> instance that represents identity,
-            authentication, and security roles for the client.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.UserEndPoint">
-            <summary>
-            Gets the endpoint from which the handshake request is sent.
-            </summary>
-            <value>
-            A <see cref="T:System.Net.IPEndPoint"/> that represents the client IP
-            address and port number.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.WebSockets.WebSocketContext.WebSocket">
-            <summary>
-            Gets the WebSocket instance used for two-way communication between
-            the client and server.
-            </summary>
-            <value>
-            A <see cref="T:WebSocketSharp.WebSocket"/>.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpBasicIdentity">
-            <summary>
-            Holds the username and password from an HTTP Basic authentication attempt.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpBasicIdentity.Password">
-            <summary>
-            Gets the password from a basic authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the password.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpDigestIdentity">
-            <summary>
-            Holds the username and other parameters from
-            an HTTP Digest authentication attempt.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Algorithm">
-            <summary>
-            Gets the algorithm parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the algorithm parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Cnonce">
-            <summary>
-            Gets the cnonce parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the cnonce parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Nc">
-            <summary>
-            Gets the nc parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the nc parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Nonce">
-            <summary>
-            Gets the nonce parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the nonce parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Opaque">
-            <summary>
-            Gets the opaque parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the opaque parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Qop">
-            <summary>
-            Gets the qop parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the qop parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Realm">
-            <summary>
-            Gets the realm parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the realm parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Response">
-            <summary>
-            Gets the response parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the response parameter.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.HttpDigestIdentity.Uri">
-            <summary>
-            Gets the uri parameter from a digest authentication attempt.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the uri parameter.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.Net.NetworkCredential">
-            <summary>
-            Provides the credentials for the password-based authentication.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.NetworkCredential.#ctor(System.String,System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.NetworkCredential"/> class with
-            the specified <paramref name="username"/> and <paramref name="password"/>.
-            </summary>
-            <param name="username">
-            A <see cref="T:System.String"/> that represents the username associated with
-            the credentials.
-            </param>
-            <param name="password">
-            A <see cref="T:System.String"/> that represents the password for the username
-            associated with the credentials.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="username"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="username"/> is empty.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.NetworkCredential.#ctor(System.String,System.String,System.String,System.String[])">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.NetworkCredential"/> class with
-            the specified <paramref name="username"/>, <paramref name="password"/>,
-            <paramref name="domain"/> and <paramref name="roles"/>.
-            </summary>
-            <param name="username">
-            A <see cref="T:System.String"/> that represents the username associated with
-            the credentials.
-            </param>
-            <param name="password">
-            A <see cref="T:System.String"/> that represents the password for the username
-            associated with the credentials.
-            </param>
-            <param name="domain">
-            A <see cref="T:System.String"/> that represents the domain associated with
-            the credentials.
-            </param>
-            <param name="roles">
-            An array of <see cref="T:System.String"/> that represents the roles
-            associated with the credentials if any.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="username"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="username"/> is empty.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.NetworkCredential.Domain">
-            <summary>
-            Gets the domain associated with the credentials.
-            </summary>
-            <remarks>
-            This property returns an empty string if the domain was
-            initialized with <see langword="null"/>.
-            </remarks>
-            <value>
-            A <see cref="T:System.String"/> that represents the domain name
-            to which the username belongs.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.NetworkCredential.Password">
-            <summary>
-            Gets the password for the username associated with the credentials.
-            </summary>
-            <remarks>
-            This property returns an empty string if the password was
-            initialized with <see langword="null"/>.
-            </remarks>
-            <value>
-            A <see cref="T:System.String"/> that represents the password.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.NetworkCredential.Roles">
-            <summary>
-            Gets the roles associated with the credentials.
-            </summary>
-            <remarks>
-            This property returns an empty array if the roles were
-            initialized with <see langword="null"/>.
-            </remarks>
-            <value>
-            An array of <see cref="T:System.String"/> that represents the role names
-            to which the username belongs.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.NetworkCredential.Username">
-            <summary>
-            Gets the username associated with the credentials.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the username.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefix.#ctor(System.String,WebSocketSharp.Net.HttpListener)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.HttpListenerPrefix"/> class
-            with the specified URI prefix and HTTP listener.
-            </summary>
-            <remarks>
-            This constructor must be called after calling the CheckPrefix method.
-            </remarks>
-            <param name="uriPrefix">
-            A <see cref="T:System.String"/> that specifies the URI prefix.
-            </param>
-            <param name="listener">
-            A <see cref="T:WebSocketSharp.Net.HttpListener"/> that specifies the HTTP listener.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefix.Equals(System.Object)">
-            <summary>
-            Determines whether the current instance is equal to the specified
-            <see cref="T:System.Object"/> instance.
-            </summary>
-            <remarks>
-            This method will be required to detect duplicates in any collection.
-            </remarks>
-            <param name="obj">
-              <para>
-              An <see cref="T:System.Object"/> instance to compare to the current instance.
-              </para>
-              <para>
-              An reference to a <see cref="T:WebSocketSharp.Net.HttpListenerPrefix"/> instance.
-              </para>
-            </param>
-            <returns>
-            <c>true</c> if the current instance and <paramref name="obj"/> have
-            the same URI prefix; otherwise, <c>false</c>.
-            </returns>
-        </member>
-        <member name="M:WebSocketSharp.Net.HttpListenerPrefix.GetHashCode">
-            <summary>
-            Gets the hash code for the current instance.
-            </summary>
-            <remarks>
-            This method will be required to detect duplicates in any collection.
-            </remarks>
-            <returns>
-            An <see cref="T:System.Int32"/> that represents the hash code.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.Net.ClientSslConfiguration">
-            <summary>
-            Stores the parameters for the <see cref="T:System.Net.Security.SslStream"/> used by clients.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.ClientSslConfiguration.#ctor(System.String)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.ClientSslConfiguration"/>
-            class with the specified target host server name.
-            </summary>
-            <param name="targetHost">
-            A <see cref="T:System.String"/> that specifies the target host server name.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="targetHost"/> is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            <paramref name="targetHost"/> is an empty string.
-            </exception>
-        </member>
-        <member name="M:WebSocketSharp.Net.ClientSslConfiguration.#ctor(WebSocketSharp.Net.ClientSslConfiguration)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.ClientSslConfiguration"/>
-            class that stores the parameters copied from the specified configuration.
-            </summary>
-            <param name="configuration">
-            A <see cref="T:WebSocketSharp.Net.ClientSslConfiguration"/> from which to copy.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="configuration"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.ClientSslConfiguration.CheckCertificateRevocation">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.ClientSslConfiguration.ClientCertificates">
-            <summary>
-            Gets or sets the collection of client certificates from which to select
-            one to supply to the server.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Security.Cryptography.X509Certificates.X509CertificateCollection"/> or <see langword="null"/>.
-              </para>
-              <para>
-              The collection contains client certificates from which to select.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.ClientSslConfiguration.ClientCertificateSelectionCallback">
-            <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="T:System.Net.Security.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>
-        </member>
-        <member name="P:WebSocketSharp.Net.ClientSslConfiguration.EnabledSslProtocols">
-            <summary>
-            Gets or sets the protocols used for authentication.
-            </summary>
-            <value>
-              <para>
-              Any of the <see cref="T:System.Security.Authentication.SslProtocols"/> enum values.
-              </para>
-              <para>
-              It represents the protocols used for authentication.
-              </para>
-              <para>
-              The default value is <see cref="F:System.Security.Authentication.SslProtocols.None"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.ClientSslConfiguration.ServerCertificateValidationCallback">
-            <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="T:System.Net.Security.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>
-        </member>
-        <member name="P:WebSocketSharp.Net.ClientSslConfiguration.TargetHost">
-            <summary>
-            Gets or sets the target host server name.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the name of the server that
-            will share a secure connection with a client.
-            </value>
-            <exception cref="T:System.ArgumentNullException">
-            The value specified for a set operation is <see langword="null"/>.
-            </exception>
-            <exception cref="T:System.ArgumentException">
-            The value specified for a set operation is an empty string.
-            </exception>
-        </member>
-        <member name="T:WebSocketSharp.Net.ServerSslConfiguration">
-            <summary>
-            Stores the parameters for the <see cref="T:System.Net.Security.SslStream"/> used by servers.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.ServerSslConfiguration.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.ServerSslConfiguration"/>
-            class.
-            </summary>
-        </member>
-        <member name="M:WebSocketSharp.Net.ServerSslConfiguration.#ctor(WebSocketSharp.Net.ServerSslConfiguration)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Net.ServerSslConfiguration"/>
-            class that stores the parameters copied from the specified configuration.
-            </summary>
-            <param name="configuration">
-            A <see cref="T:WebSocketSharp.Net.ServerSslConfiguration"/> from which to copy.
-            </param>
-            <exception cref="T:System.ArgumentNullException">
-            <paramref name="configuration"/> is <see langword="null"/>.
-            </exception>
-        </member>
-        <member name="P:WebSocketSharp.Net.ServerSslConfiguration.CheckCertificateRevocation">
-            <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>
-        </member>
-        <member name="P:WebSocketSharp.Net.ServerSslConfiguration.ClientCertificateRequired">
-            <summary>
-            Gets or sets a value indicating whether the client is asked for
-            a certificate for authentication.
-            </summary>
-            <value>
-              <para>
-              <c>true</c> if the client is asked for a certificate for
-              authentication; otherwise, <c>false</c>.
-              </para>
-              <para>
-              The default value is <c>false</c>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.ServerSslConfiguration.ClientCertificateValidationCallback">
-            <summary>
-            Gets or sets the callback used to validate the certificate supplied by
-            the client.
-            </summary>
-            <remarks>
-            The certificate is valid if the callback returns <c>true</c>.
-            </remarks>
-            <value>
-              <para>
-              A <see cref="T:System.Net.Security.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>
-        </member>
-        <member name="P:WebSocketSharp.Net.ServerSslConfiguration.EnabledSslProtocols">
-            <summary>
-            Gets or sets the protocols used for authentication.
-            </summary>
-            <value>
-              <para>
-              Any of the <see cref="T:System.Security.Authentication.SslProtocols"/> enum values.
-              </para>
-              <para>
-              It represents the protocols used for authentication.
-              </para>
-              <para>
-              The default value is <see cref="F:System.Security.Authentication.SslProtocols.None"/>.
-              </para>
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Net.ServerSslConfiguration.ServerCertificate">
-            <summary>
-            Gets or sets the certificate used to authenticate the server.
-            </summary>
-            <value>
-              <para>
-              A <see cref="T:System.Security.Cryptography.X509Certificates.X509Certificate2"/> or <see langword="null"/>.
-              </para>
-              <para>
-              The certificate represents an X.509 certificate.
-              </para>
-              <para>
-              The default value is <see langword="null"/>.
-              </para>
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpRequestHeader">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.CacheControl">
-            <summary>
-            Indicates the Cache-Control header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Connection">
-            <summary>
-            Indicates the Connection header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Date">
-            <summary>
-            Indicates the Date header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.KeepAlive">
-            <summary>
-            Indicates the Keep-Alive header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Pragma">
-            <summary>
-            Indicates the Pragma header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Trailer">
-            <summary>
-            Indicates the Trailer header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.TransferEncoding">
-            <summary>
-            Indicates the Transfer-Encoding header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Upgrade">
-            <summary>
-            Indicates the Upgrade header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Via">
-            <summary>
-            Indicates the Via header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Warning">
-            <summary>
-            Indicates the Warning header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Allow">
-            <summary>
-            Indicates the Allow header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentLength">
-            <summary>
-            Indicates the Content-Length header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentType">
-            <summary>
-            Indicates the Content-Type header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentEncoding">
-            <summary>
-            Indicates the Content-Encoding header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentLanguage">
-            <summary>
-            Indicates the Content-Language header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentLocation">
-            <summary>
-            Indicates the Content-Location header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentMd5">
-            <summary>
-            Indicates the Content-MD5 header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ContentRange">
-            <summary>
-            Indicates the Content-Range header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Expires">
-            <summary>
-            Indicates the Expires header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.LastModified">
-            <summary>
-            Indicates the Last-Modified header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Accept">
-            <summary>
-            Indicates the Accept header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.AcceptCharset">
-            <summary>
-            Indicates the Accept-Charset header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.AcceptEncoding">
-            <summary>
-            Indicates the Accept-Encoding header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.AcceptLanguage">
-            <summary>
-            Indicates the Accept-Language header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Authorization">
-            <summary>
-            Indicates the Authorization header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Cookie">
-            <summary>
-            Indicates the Cookie header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Expect">
-            <summary>
-            Indicates the Expect header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.From">
-            <summary>
-            Indicates the From header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Host">
-            <summary>
-            Indicates the Host header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.IfMatch">
-            <summary>
-            Indicates the If-Match header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.IfModifiedSince">
-            <summary>
-            Indicates the If-Modified-Since header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.IfNoneMatch">
-            <summary>
-            Indicates the If-None-Match header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.IfRange">
-            <summary>
-            Indicates the If-Range header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.IfUnmodifiedSince">
-            <summary>
-            Indicates the If-Unmodified-Since header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.MaxForwards">
-            <summary>
-            Indicates the Max-Forwards header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.ProxyAuthorization">
-            <summary>
-            Indicates the Proxy-Authorization header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Referer">
-            <summary>
-            Indicates the Referer header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Range">
-            <summary>
-            Indicates the Range header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Te">
-            <summary>
-            Indicates the TE header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.Translate">
-            <summary>
-            Indicates the Translate header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.UserAgent">
-            <summary>
-            Indicates the User-Agent header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.SecWebSocketKey">
-            <summary>
-            Indicates the Sec-WebSocket-Key header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.SecWebSocketExtensions">
-            <summary>
-            Indicates the Sec-WebSocket-Extensions header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.SecWebSocketProtocol">
-            <summary>
-            Indicates the Sec-WebSocket-Protocol header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpRequestHeader.SecWebSocketVersion">
-            <summary>
-            Indicates the Sec-WebSocket-Version header.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Net.HttpResponseHeader">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.CacheControl">
-            <summary>
-            Indicates the Cache-Control header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Connection">
-            <summary>
-            Indicates the Connection header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Date">
-            <summary>
-            Indicates the Date header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.KeepAlive">
-            <summary>
-            Indicates the Keep-Alive header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Pragma">
-            <summary>
-            Indicates the Pragma header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Trailer">
-            <summary>
-            Indicates the Trailer header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.TransferEncoding">
-            <summary>
-            Indicates the Transfer-Encoding header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Upgrade">
-            <summary>
-            Indicates the Upgrade header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Via">
-            <summary>
-            Indicates the Via header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Warning">
-            <summary>
-            Indicates the Warning header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Allow">
-            <summary>
-            Indicates the Allow header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentLength">
-            <summary>
-            Indicates the Content-Length header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentType">
-            <summary>
-            Indicates the Content-Type header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentEncoding">
-            <summary>
-            Indicates the Content-Encoding header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentLanguage">
-            <summary>
-            Indicates the Content-Language header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentLocation">
-            <summary>
-            Indicates the Content-Location header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentMd5">
-            <summary>
-            Indicates the Content-MD5 header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ContentRange">
-            <summary>
-            Indicates the Content-Range header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Expires">
-            <summary>
-            Indicates the Expires header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.LastModified">
-            <summary>
-            Indicates the Last-Modified header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.AcceptRanges">
-            <summary>
-            Indicates the Accept-Ranges header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Age">
-            <summary>
-            Indicates the Age header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ETag">
-            <summary>
-            Indicates the ETag header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Location">
-            <summary>
-            Indicates the Location header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.ProxyAuthenticate">
-            <summary>
-            Indicates the Proxy-Authenticate header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.RetryAfter">
-            <summary>
-            Indicates the Retry-After header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Server">
-            <summary>
-            Indicates the Server header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.SetCookie">
-            <summary>
-            Indicates the Set-Cookie header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.Vary">
-            <summary>
-            Indicates the Vary header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.WwwAuthenticate">
-            <summary>
-            Indicates the WWW-Authenticate header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.SecWebSocketExtensions">
-            <summary>
-            Indicates the Sec-WebSocket-Extensions header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.SecWebSocketAccept">
-            <summary>
-            Indicates the Sec-WebSocket-Accept header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.SecWebSocketProtocol">
-            <summary>
-            Indicates the Sec-WebSocket-Protocol header.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Net.HttpResponseHeader.SecWebSocketVersion">
-            <summary>
-            Indicates the Sec-WebSocket-Version header.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.CloseStatusCode">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.Normal">
-            <summary>
-            Equivalent to close status 1000. Indicates normal close.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.Away">
-            <summary>
-            Equivalent to close status 1001. Indicates that an endpoint is
-            going away.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.ProtocolError">
-            <summary>
-            Equivalent to close status 1002. Indicates that an endpoint is
-            terminating the connection due to a protocol error.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.UnsupportedData">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.Undefined">
-            <summary>
-            Equivalent to close status 1004. Still undefined. A Reserved value.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.NoStatus">
-            <summary>
-            Equivalent to close status 1005. Indicates that no status code was
-            actually present. A Reserved value.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.Abnormal">
-            <summary>
-            Equivalent to close status 1006. Indicates that the connection was
-            closed abnormally. A Reserved value.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.InvalidData">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.PolicyViolation">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.TooBig">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.MandatoryExtension">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.ServerError">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CloseStatusCode.TlsHandshakeFailure">
-            <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>
-        </member>
-        <member name="T:WebSocketSharp.Fin">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Fin.More">
-            <summary>
-            Equivalent to numeric value 0. Indicates more frames of a message follow.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Fin.Final">
-            <summary>
-            Equivalent to numeric value 1. Indicates the final frame of a message.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Mask">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.Mask.Off">
-            <summary>
-            Equivalent to numeric value 0. Indicates not masked.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Mask.On">
-            <summary>
-            Equivalent to numeric value 1. Indicates masked.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Opcode">
-            <summary>
-            Indicates the WebSocket frame type.
-            </summary>
-            <remarks>
-            The values of this enumeration are defined in
-            <see href="http://tools.ietf.org/html/rfc6455#section-5.2">
-            Section 5.2</see> of RFC 6455.
-            </remarks>
-        </member>
-        <member name="F:WebSocketSharp.Opcode.Cont">
-            <summary>
-            Equivalent to numeric value 0. Indicates continuation frame.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Opcode.Text">
-            <summary>
-            Equivalent to numeric value 1. Indicates text frame.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Opcode.Binary">
-            <summary>
-            Equivalent to numeric value 2. Indicates binary frame.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Opcode.Close">
-            <summary>
-            Equivalent to numeric value 8. Indicates connection close frame.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Opcode.Ping">
-            <summary>
-            Equivalent to numeric value 9. Indicates ping frame.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Opcode.Pong">
-            <summary>
-            Equivalent to numeric value 10. Indicates pong frame.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.PayloadData.Empty">
-            <summary>
-            Represents the empty payload data.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.PayloadData.MaxLength">
-            <summary>
-            Represents the allowable max length of payload data.
-            </summary>
-            <remarks>
-              <para>
-              A <see cref="T:WebSocketSharp.WebSocketException"/> will occur when the length of
-              incoming payload data is greater than the value of this field.
-              </para>
-              <para>
-              If you would like to change the value of this field, it must be
-              a number between <see cref="F:WebSocketSharp.WebSocket.FragmentLength"/> and
-              <see cref="F:System.Int64.MaxValue"/> inclusive.
-              </para>
-            </remarks>
-        </member>
-        <member name="T:WebSocketSharp.Rsv">
-            <summary>
-            Indicates whether each RSV (RSV1, RSV2, and RSV3) of a WebSocket frame is non-zero.
-            </summary>
-            <remarks>
-            The values of this enumeration are defined in
-            <see href="http://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2</see> of RFC 6455.
-            </remarks>
-        </member>
-        <member name="F:WebSocketSharp.Rsv.Off">
-            <summary>
-            Equivalent to numeric value 0. Indicates zero.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.Rsv.On">
-            <summary>
-            Equivalent to numeric value 1. Indicates non-zero.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.CompressionMethod">
-            <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>
-        </member>
-        <member name="F:WebSocketSharp.CompressionMethod.None">
-            <summary>
-            Specifies no compression.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.CompressionMethod.Deflate">
-            <summary>
-            Specifies DEFLATE.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.WebSocketException">
-            <summary>
-            The exception that is thrown when a fatal error occurs in
-            the WebSocket communication.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.WebSocketException.Code">
-            <summary>
-            Gets the status code indicating the cause of the exception.
-            </summary>
-            <value>
-            One of the <see cref="T:WebSocketSharp.CloseStatusCode"/> enum values that represents
-            the status code indicating the cause of the exception.
-            </value>
-        </member>
-        <member name="T:WebSocketSharp.LogData">
-            <summary>
-            Represents a log data used by the <see cref="T:WebSocketSharp.Logger"/> class.
-            </summary>
-        </member>
-        <member name="P:WebSocketSharp.LogData.Caller">
-            <summary>
-            Gets the information of the logging method caller.
-            </summary>
-            <value>
-            A <see cref="T:System.Diagnostics.StackFrame"/> that provides the information of the logging method caller.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.LogData.Date">
-            <summary>
-            Gets the date and time when the log data was created.
-            </summary>
-            <value>
-            A <see cref="T:System.DateTime"/> that represents the date and time when the log data was created.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.LogData.Level">
-            <summary>
-            Gets the logging level of the log data.
-            </summary>
-            <value>
-            One of the <see cref="T:WebSocketSharp.LogLevel"/> enum values, indicates the logging level of the log data.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.LogData.Message">
-            <summary>
-            Gets the message of the log data.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the message of the log data.
-            </value>
-        </member>
-        <member name="M:WebSocketSharp.LogData.ToString">
-            <summary>
-            Returns a <see cref="T:System.String"/> that represents the current <see cref="T:WebSocketSharp.LogData"/>.
-            </summary>
-            <returns>
-            A <see cref="T:System.String"/> that represents the current <see cref="T:WebSocketSharp.LogData"/>.
-            </returns>
-        </member>
-        <member name="T:WebSocketSharp.LogLevel">
-            <summary>
-            Specifies the logging level.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.LogLevel.Trace">
-            <summary>
-            Specifies the bottom logging level.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.LogLevel.Debug">
-            <summary>
-            Specifies the 2nd logging level from the bottom.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.LogLevel.Info">
-            <summary>
-            Specifies the 3rd logging level from the bottom.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.LogLevel.Warn">
-            <summary>
-            Specifies the 3rd logging level from the top.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.LogLevel.Error">
-            <summary>
-            Specifies the 2nd logging level from the top.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.LogLevel.Fatal">
-            <summary>
-            Specifies the top logging level.
-            </summary>
-        </member>
-        <member name="T:WebSocketSharp.Logger">
-            <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="P:WebSocketSharp.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="P:WebSocketSharp.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="P:WebSocketSharp.Logger.Output"/> property to any <c>Action&lt;LogData, string&gt;</c>
-              delegate.
-              </para>
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Logger.#ctor">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Logger"/> class.
-            </summary>
-            <remarks>
-            This constructor initializes the current logging level with <see cref="F:WebSocketSharp.LogLevel.Error"/>.
-            </remarks>
-        </member>
-        <member name="M:WebSocketSharp.Logger.#ctor(WebSocketSharp.LogLevel)">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.Logger"/> class with
-            the specified logging <paramref name="level"/>.
-            </summary>
-            <param name="level">
-            One of the <see cref="T:WebSocketSharp.LogLevel"/> enum values.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Logger.#ctor(WebSocketSharp.LogLevel,System.String,System.Action{WebSocketSharp.LogData,System.String})">
-            <summary>
-            Initializes a new instance of the <see cref="T:WebSocketSharp.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="T:WebSocketSharp.LogLevel"/> enum values.
-            </param>
-            <param name="file">
-            A <see cref="T:System.String"/> that represents the path to the log file.
-            </param>
-            <param name="output">
-            An <c>Action&lt;LogData, string&gt;</c> delegate that references the method(s) used to
-            output a log. A <see cref="T:System.String"/> parameter passed to this delegate is
-            <paramref name="file"/>.
-            </param>
-        </member>
-        <member name="P:WebSocketSharp.Logger.File">
-            <summary>
-            Gets or sets the current path to the log file.
-            </summary>
-            <value>
-            A <see cref="T:System.String"/> that represents the current path to the log file if any.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Logger.Level">
-            <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="T:WebSocketSharp.LogLevel"/> enum values, specifies the current logging level.
-            </value>
-        </member>
-        <member name="P:WebSocketSharp.Logger.Output">
-            <summary>
-            Gets or sets the current output action used to output a log.
-            </summary>
-            <value>
-              <para>
-              An <c>Action&lt;LogData, string&gt;</c> delegate that references the method(s) used to
-              output a log. A <see cref="T:System.String"/> parameter passed to this delegate is the value of
-              the <see cref="P:WebSocketSharp.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>
-        </member>
-        <member name="M:WebSocketSharp.Logger.Debug(System.String)">
-            <summary>
-            Outputs <paramref name="message"/> as a log with <see cref="F:WebSocketSharp.LogLevel.Debug"/>.
-            </summary>
-            <remarks>
-            If the current logging level is higher than <see cref="F:WebSocketSharp.LogLevel.Debug"/>,
-            this method doesn't output <paramref name="message"/> as a log.
-            </remarks>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the message to output as a log.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Logger.Error(System.String)">
-            <summary>
-            Outputs <paramref name="message"/> as a log with <see cref="F:WebSocketSharp.LogLevel.Error"/>.
-            </summary>
-            <remarks>
-            If the current logging level is higher than <see cref="F:WebSocketSharp.LogLevel.Error"/>,
-            this method doesn't output <paramref name="message"/> as a log.
-            </remarks>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the message to output as a log.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Logger.Fatal(System.String)">
-            <summary>
-            Outputs <paramref name="message"/> as a log with <see cref="F:WebSocketSharp.LogLevel.Fatal"/>.
-            </summary>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the message to output as a log.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Logger.Info(System.String)">
-            <summary>
-            Outputs <paramref name="message"/> as a log with <see cref="F:WebSocketSharp.LogLevel.Info"/>.
-            </summary>
-            <remarks>
-            If the current logging level is higher than <see cref="F:WebSocketSharp.LogLevel.Info"/>,
-            this method doesn't output <paramref name="message"/> as a log.
-            </remarks>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the message to output as a log.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Logger.Trace(System.String)">
-            <summary>
-            Outputs <paramref name="message"/> as a log with <see cref="F:WebSocketSharp.LogLevel.Trace"/>.
-            </summary>
-            <remarks>
-            If the current logging level is higher than <see cref="F:WebSocketSharp.LogLevel.Trace"/>,
-            this method doesn't output <paramref name="message"/> as a log.
-            </remarks>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the message to output as a log.
-            </param>
-        </member>
-        <member name="M:WebSocketSharp.Logger.Warn(System.String)">
-            <summary>
-            Outputs <paramref name="message"/> as a log with <see cref="F:WebSocketSharp.LogLevel.Warn"/>.
-            </summary>
-            <remarks>
-            If the current logging level is higher than <see cref="F:WebSocketSharp.LogLevel.Warn"/>,
-            this method doesn't output <paramref name="message"/> as a log.
-            </remarks>
-            <param name="message">
-            A <see cref="T:System.String"/> that represents the message to output as a log.
-            </param>
-        </member>
-        <member name="T:WebSocketSharp.WebSocketState">
-            <summary>
-            Indicates the state of a WebSocket connection.
-            </summary>
-            <remarks>
-            The values of this enumeration are defined in
-            <see href="http://www.w3.org/TR/websockets/#dom-websocket-readystate">
-            The WebSocket API</see>.
-            </remarks>
-        </member>
-        <member name="F:WebSocketSharp.WebSocketState.Connecting">
-            <summary>
-            Equivalent to numeric value 0. Indicates that the connection has not
-            yet been established.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.WebSocketState.Open">
-            <summary>
-            Equivalent to numeric value 1. Indicates that the connection has
-            been established, and the communication is possible.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.WebSocketState.Closing">
-            <summary>
-            Equivalent to numeric value 2. Indicates that the connection is
-            going through the closing handshake, or the close method has
-            been invoked.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.WebSocketState.Closed">
-            <summary>
-            Equivalent to numeric value 3. Indicates that the connection has
-            been closed or could not be established.
-            </summary>
-        </member>
-        <member name="F:WebSocketSharp.WebSocketFrame.EmptyPingBytes">
-            <summary>
-            Represents the ping frame without the payload data as an array of
-            <see cref="T:System.Byte"/>.
-            </summary>
-            <remarks>
-            The value of this field is created from a non masked ping frame,
-            so it can only be used to send a ping from the server.
-            </remarks>
-        </member>
-    </members>
-</doc>

+ 10 - 1
src/UnitTests/RamTests.cs

@@ -21,11 +21,20 @@ namespace NTMiner {
             NTStopwatch.Start();
 
             for (int i = 0; i < 500; i++) {
-                var v = VirtualRoot.ProcessMemoryMb;
+                _ = VirtualRoot.ProcessMemoryMb;
+                _ = VirtualRoot.ThreadCount;
+                _ = VirtualRoot.HandleCount;
             }
 
             var elapsedMilliseconds = NTStopwatch.Stop();
             Console.WriteLine(elapsedMilliseconds);
         }
+
+        [TestMethod]
+        public void Test2() {
+            Console.WriteLine(VirtualRoot.ProcessMemoryMb);
+            Console.WriteLine(VirtualRoot.ThreadCount);
+            Console.WriteLine(VirtualRoot.HandleCount);
+        }
     }
 }

+ 14 - 0
src/UnitTests/ReflectionTests.cs

@@ -109,6 +109,20 @@ namespace NTMiner {
             Console.WriteLine(elapsedMilliseconds);
         }
 
+        [TestMethod]
+        public void BenchmarkTest1() {
+            // 非常快,无性能问题,即使不是返回null值的单元测试程序下也非常快
+            int n = 10000;
+            Assert.IsNull(Assembly.GetEntryAssembly());
+            Assert.IsTrue(DevMode.IsInUnitTest);
+            NTStopwatch.Start();
+            for (int i = 0; i < n; i++) {
+                _ = Assembly.GetEntryAssembly();
+            }
+            var elapsedMilliseconds = NTStopwatch.Stop();
+            Console.WriteLine(elapsedMilliseconds);
+        }
+
         [TestMethod]
         public void AdlNativeMethodsTest() {
             Type t = typeof(Gpus.Adl.AdlNativeMethods);

+ 20 - 0
src/UnitTests/ShardingHasherTests.cs

@@ -6,6 +6,26 @@ using System.Collections.Generic;
 namespace NTMiner {
     [TestClass]
     public class ShardingHasherTests {
+        [TestMethod]
+        public void Test() {
+            var nodes = new string[] { "1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4", "5.5.5.5" };
+            ShardingHasher shardingHasher = new ShardingHasher(nodes);
+            for (int i = 0; i < 1000; i++) {
+                Guid guid = Guid.NewGuid();
+                Assert.AreEqual(shardingHasher.GetTargetNode(guid), shardingHasher.GetTargetNode(guid));
+            }
+            Dictionary<Guid, string> dic = new Dictionary<Guid, string>();
+            for (int i = 0; i < 1000; i++) {
+                Guid guid = Guid.NewGuid();
+                dic[guid] = shardingHasher.GetTargetNode(guid);
+            }
+            nodes = new string[] { "2.2.2.2", "1.1.1.1", "4.4.4.4", "3.3.3.3", "5.5.5.5" };
+            shardingHasher = new ShardingHasher(nodes);
+            foreach (var guid in dic.Keys) {
+                Assert.AreEqual(dic[guid], shardingHasher.GetTargetNode(guid));
+            }
+        }
+
         [TestMethod]
         public void Test1() {
             var nodes = new string[] { "1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4", "5.5.5.5" };

+ 1 - 1
src/UserServer/AppRoot.cs

@@ -13,7 +13,7 @@ namespace NTMiner {
             Console.ForegroundColor = ConsoleColor.Gray;
             Console.WriteLine("这是开源矿工外网群控服务端程序,和官方运行的服务端功能上完全一样,唯一的区别是官方程序运行在集群上,这个程序运行在用户自己的比如阿里云服务器上,如果您没有上千台矿机建议您直接连接官方的外网群控服务器。");
             Console.ForegroundColor = defaultColor;
-
+            // TODO:搁置,以后再实现,只要能保证官方外网服务器集群的可用性就不需要用户自己部署外网服务器
             Console.WriteLine();
             Console.WriteLine("按任意键退出");
             Console.ReadKey();

+ 4 - 3
src/UserServer/UserServer.csproj

@@ -46,9 +46,6 @@
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
-    <Reference Include="websocket-sharp">
-      <HintPath>..\ThirdPartyDlls\websocket-sharp.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AppRoot.cs" />
@@ -79,6 +76,10 @@
       <Project>{e12eefdc-66e9-4b7d-a036-fc1d4962eb04}</Project>
       <Name>ServerCommon</Name>
     </ProjectReference>
+    <ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
+      <Project>{b357bac7-529e-4d81-a0d2-71041b19c8de}</Project>
+      <Name>websocket-sharp</Name>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

+ 3 - 1
src/WebApiServer/AppRoot.cs

@@ -235,7 +235,9 @@ namespace NTMiner {
                 Cpu = cpu.ToData(),
                 OSInfo = Windows.OS.Instance.OsInfo,
                 CpuPerformance = cpu.GetTotalCpuUsage(),
-                ProcessMemoryMb = VirtualRoot.ProcessMemoryMb
+                ProcessMemoryMb = VirtualRoot.ProcessMemoryMb,
+                ThreadCount = VirtualRoot.ThreadCount,
+                HandleCount = VirtualRoot.HandleCount
             };
         }
 

+ 5 - 2
src/WsServer/Core/ISession.cs

@@ -28,12 +28,15 @@ namespace NTMiner.Core {
         /// <remarks>注意这里说的进程不是指的操作系统进程而是指运行中的开源矿工程序</remarks>
         Version ClientVersion { get; }
         /// <summary>
-        /// 会话的最新活动时间。清洁工线程会依据该值判断是否要清理掉不活跃的连接对应的资源。
+        /// 会话的最新活动时间戳,该时间戳在收到Ping的时候更新。清洁工线程会依据该值判断是否要清理掉不活跃的连接对应的资源。
         /// </summary>
         DateTime ActiveOn { get; }
+        /// <summary>
+        /// Ws会话远端的IP地址和端口号,该数据可以用于统计。
+        /// </summary>
         IPEndPoint RemoteEndPoint { get; }
         /// <summary>
-        /// 这是所使用的WebSocket框架层为当前会话分配的会话标识。
+        /// 这是所使用的WebSocket框架层为当前会话分配的会话标识,根据这个标识可以找到WebSocket会话从而向远端发送信息
         /// </summary>
         string WsSessionId { get; }
         /// <summary>

+ 7 - 1
src/WsServer/Core/Impl/AbstractSession.cs

@@ -11,7 +11,13 @@ namespace NTMiner.Core.Impl {
         /// </summary>
         /// <param name="user"></param>
         /// <param name="wsSessionID"></param>
-        public AbstractSession(IUser user, WsUserName wsUserName, IPEndPoint remoteEndPoint, string wsSessionID, IWsSessionsAdapter wsSessions) {
+        public AbstractSession(
+            IUser user, 
+            WsUserName wsUserName, 
+            IPEndPoint remoteEndPoint, 
+            string wsSessionID, 
+            IWsSessionsAdapter wsSessions) {
+
             _wsSessions = wsSessions;
             this.WsUserName = wsUserName;
             this.ClientId = wsUserName.ClientId;

+ 4 - 9
src/WsServer/Core/Impl/AbstractSessionSet`1.cs

@@ -110,7 +110,7 @@ namespace NTMiner.Core.Impl {
                 }
             }
             if (toRemoves.Count > 0) {
-                NTMinerConsole.UserWarn($"周期清理不活跃的{_sessionType.Name},清理了 {toRemoves.Count.ToString()}/{toRemoves.Count.ToString()} 条");
+                NTMinerConsole.UserWarn($"周期清理不活跃的{_sessionType.Name},清理了 {toRemoves.Count.ToString()} 条");
             }
         }
 
@@ -160,18 +160,13 @@ namespace NTMiner.Core.Impl {
 
         public bool ActiveByWsSessionId(string wsSessionId, out TSession ntminerSession) {
             if (TryGetByWsSessionId(wsSessionId, out ntminerSession)) {
-                if (TryGetByClientId(ntminerSession.ClientId, out TSession sessionByClientId)) {
-                    if (sessionByClientId.WsSessionId == wsSessionId) {
-                        ntminerSession.Active();
-                        return true;
-                    }
-                }
-                else {
+                if (!TryGetByClientId(ntminerSession.ClientId, out TSession _)) {
                     lock (_locker) {
                         _dicByClientId[ntminerSession.ClientId] = ntminerSession;
                     }
-                    return true;
                 }
+                ntminerSession.Active();
+                return true;
             }
             return false;
         }

+ 2 - 1
src/WsServer/Core/Impl/MinerClientSessionSet.cs

@@ -3,6 +3,7 @@ using NTMiner.Core.MinerServer;
 using NTMiner.User;
 using NTMiner.Ws;
 using System;
+using System.Linq;
 
 namespace NTMiner.Core.Impl {
     public class MinerClientSessionSet : AbstractSessionSet<IMinerClientSession>, IMinerClientSessionSet {
@@ -65,7 +66,7 @@ namespace NTMiner.Core.Impl {
                 if (user == null) {
                     return;
                 }
-                foreach (var clientId in message.ClientIds) {
+                foreach (var clientId in message.ClientIds.Where(a => TryGetByClientId(a, out _))) {
                     if (clientId == null || clientId == Guid.Empty) {
                         continue;
                     }

+ 6 - 0
src/WsServer/Core/Impl/MinerSignSet.cs

@@ -24,6 +24,7 @@ namespace NTMiner.Core.Impl {
             });
             // 收到Mq消息之前一定已经初始化完成,因为Mq消费者在MinerSignSetInitedEvent事件之后才会创建
             VirtualRoot.BuildEventPath<MinerDataRemovedMqMessage>("收到MinerClientRemovedMq消息后移除内存中对应的记录", LogEnum.None, path: message => {
+                #region
                 if (message.AppId == ServerRoot.HostConfig.ThisServerAddress) {
                     return;
                 }
@@ -41,8 +42,10 @@ namespace NTMiner.Core.Impl {
                     _dicByMinerId.Remove(message.MinerId);
                     _dicByClientId.Remove(minerSign.ClientId);
                 }
+                #endregion
             }, this.GetType());
             VirtualRoot.BuildEventPath<MinerDataAddedMqMessage>("收到MinerDataAddedMq消息后更新内存中对应的记录", LogEnum.None, path: message => {
+                #region
                 if (message.AppId == ServerRoot.HostConfig.ThisServerAddress) {
                     return;
                 }
@@ -63,8 +66,10 @@ namespace NTMiner.Core.Impl {
                         }
                     }
                 });
+                #endregion
             }, this.GetType());
             VirtualRoot.BuildEventPath<MinerSignChangedMqMessage>("收到MinerSignChangedMq消息后更新内存中对应的记录", LogEnum.None, path: message => {
+                #region
                 if (message.AppId == ServerRoot.HostConfig.ThisServerAddress) {
                     return;
                 }
@@ -85,6 +90,7 @@ namespace NTMiner.Core.Impl {
                         }
                     }
                 });
+                #endregion
             }, this.GetType());
         }
 

+ 38 - 32
src/WsServer/Core/Impl/WsServerNodeAddressSet.cs

@@ -2,6 +2,7 @@
 using NTMiner.Core.Redis;
 using NTMiner.ServerNode;
 using System;
+using System.Threading.Tasks;
 
 namespace NTMiner.Core.Impl {
     public class WsServerNodeAddressSet : WsServerNodeAddressSetBase, IWsServerNodeAddressSet {
@@ -25,40 +26,45 @@ namespace NTMiner.Core.Impl {
         }
 
         private void ReportNodeAsync(Action callback = null) {
-            WsServerNodeState nodeState = null;
-            try {
-                int minerClientWsSessionCount = 0;
-                int minerStudioWsSessionCount = 0;
-                minerClientWsSessionCount = AppRoot.WsServer.MinerClientWsSessions.Count;
-                minerStudioWsSessionCount = AppRoot.WsServer.MinerStudioWsSessions.Count;
-                var ram = Windows.Ram.Instance;
-                var cpu = Windows.Cpu.Instance;
-                nodeState = new WsServerNodeState {
-                    Address = ServerRoot.HostConfig.ThisServerAddress,
-                    Description = string.Empty,
-                    MinerClientSessionCount = AppRoot.MinerClientSessionSet.Count,
-                    MinerStudioSessionCount = AppRoot.MinerStudioSessionSet.Count,
-                    MinerClientWsSessionCount = minerClientWsSessionCount,
-                    MinerStudioWsSessionCount = minerStudioWsSessionCount,
-                    Cpu = cpu.ToData(),
-                    TotalPhysicalMemory = ram.TotalPhysicalMemory,
-                    AvailablePhysicalMemory = ram.AvailablePhysicalMemory,
-                    OSInfo = Windows.OS.Instance.OsInfo,
-                    CpuPerformance = cpu.GetTotalCpuUsage(),
-                    ProcessMemoryMb = VirtualRoot.ProcessMemoryMb
-                };
-            }
-            catch (Exception e) {
-                Logger.ErrorDebugLine(e);
-            }
-            _wsServerNodeRedis.SetAsync(nodeState).ContinueWith(t => {
-                if (t.Exception != null) {
-                    NTMinerConsole.UserFail("呼吸失败:" + t.Exception.Message);
+            Task.Factory.StartNew(() => {
+                WsServerNodeState nodeState = null;
+                try {
+                    int minerClientWsSessionCount = 0;
+                    int minerStudioWsSessionCount = 0;
+                    minerClientWsSessionCount = AppRoot.WsServer.MinerClientWsSessions.Count;
+                    minerStudioWsSessionCount = AppRoot.WsServer.MinerStudioWsSessions.Count;
+                    var ram = Windows.Ram.Instance;
+                    var cpu = Windows.Cpu.Instance;
+                    nodeState = new WsServerNodeState {
+                        Address = ServerRoot.HostConfig.ThisServerAddress,
+                        Description = string.Empty,
+                        MinerClientSessionCount = AppRoot.MinerClientSessionSet.Count,
+                        MinerStudioSessionCount = AppRoot.MinerStudioSessionSet.Count,
+                        MinerClientWsSessionCount = minerClientWsSessionCount,
+                        MinerStudioWsSessionCount = minerStudioWsSessionCount,
+                        Cpu = cpu.ToData(),
+                        TotalPhysicalMemory = ram.TotalPhysicalMemory,
+                        AvailablePhysicalMemory = ram.AvailablePhysicalMemory,
+                        OSInfo = Windows.OS.Instance.OsInfo,
+                        CpuPerformance = cpu.GetTotalCpuUsage(),
+                        // 以下三个属性的访问约耗时30毫秒所以放在Task中
+                        ProcessMemoryMb = VirtualRoot.ProcessMemoryMb,
+                        ThreadCount = VirtualRoot.ThreadCount,
+                        HandleCount = VirtualRoot.HandleCount
+                    };
                 }
-                else {
-                    NTMinerConsole.UserOk("呼吸成功");
+                catch (Exception e) {
+                    Logger.ErrorDebugLine(e);
                 }
-                callback?.Invoke();
+                _wsServerNodeRedis.SetAsync(nodeState).ContinueWith(t => {
+                    if (t.Exception != null) {
+                        NTMinerConsole.UserFail("呼吸失败:" + t.Exception.Message);
+                    }
+                    else {
+                        NTMinerConsole.UserOk("呼吸成功");
+                    }
+                    callback?.Invoke();
+                });
             });
         }
     }

+ 4 - 3
src/WsServer/WsServer.csproj

@@ -68,9 +68,6 @@
     <Reference Include="System.IO.Compression" />
     <Reference Include="System.Management" />
     <Reference Include="System.Web" />
-    <Reference Include="websocket-sharp">
-      <HintPath>..\ThirdPartyDlls\websocket-sharp.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Core\IMinerSignSet.cs" />
@@ -147,6 +144,10 @@
       <Project>{e12eefdc-66e9-4b7d-a036-fc1d4962eb04}</Project>
       <Name>ServerCommon</Name>
     </ProjectReference>
+    <ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
+      <Project>{b357bac7-529e-4d81-a0d2-71041b19c8de}</Project>
+      <Name>websocket-sharp</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />

+ 1 - 1
src/WsServer/WsSharp/SharpWsServerAdapter.cs

@@ -27,7 +27,7 @@ namespace NTMiner.WsSharp {
                 }
             };
             //_wsServer.Log.Level = WebSocketSharp.LogLevel.Debug;
-            _wsServer.Log.File = TempPath.WebSocketSharpMinerStudioLogFileFullName;
+            _wsServer.Log.File = Path.Combine(HomePath.HomeLogsDirFullName, NTKeyword.WebSocketSharpMinerStudioLogFileName);
             _wsServer.Log.Output = (data, path) => {
                 Console.WriteLine(data.Message);
                 if (path != null && path.Length > 0) {

+ 26 - 0
src/websocket-sharp/AssemblyInfo.cs

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

+ 47 - 0
src/websocket-sharp/ByteOrder.cs

@@ -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 - 0
src/websocket-sharp/CloseEventArgs.cs

@@ -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 - 0
src/websocket-sharp/CloseStatusCode.cs

@@ -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 - 0
src/websocket-sharp/CompressionMethod.cs

@@ -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 - 0
src/websocket-sharp/ErrorEventArgs.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 2146 - 0
src/websocket-sharp/Ext.cs

@@ -0,0 +1,2146 @@
+#region License
+/*
+ * Ext.cs
+ *
+ * Some parts of this code are derived from Mono (http://www.mono-project.com):
+ * - GetStatusDescription is derived from HttpListenerResponse.cs (System.Net)
+ * - IsPredefinedScheme is derived from Uri.cs (System)
+ * - MaybeUri is derived from Uri.cs (System)
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2001 Garrett Rooney
+ * Copyright (c) 2003 Ian MacLean
+ * Copyright (c) 2003 Ben Maurer
+ * Copyright (c) 2003, 2005, 2009 Novell, Inc. (http://www.novell.com)
+ * Copyright (c) 2009 Stephane Delcroix
+ * Copyright (c) 2010-2016 sta.blockhead
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#endregion
+
+#region Contributors
+/*
+ * Contributors:
+ * - Liryna <[email protected]>
+ * - Nikola Kovacevic <[email protected]>
+ * - Chris Swiedler
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.IO.Compression;
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using WebSocketSharp.Net;
+using WebSocketSharp.Net.WebSockets;
+using WebSocketSharp.Server;
+
+namespace WebSocketSharp {
+    /// <summary>
+    /// Provides a set of static methods for websocket-sharp.
+    /// </summary>
+    public static class Ext {
+        #region Private Fields
+
+        private static readonly byte[] _last = new byte[] { 0x00 };
+        private static readonly int _retry = 5;
+        private const string _tspecials = "()<>@,;:\\\"/[]?={} \t";
+
+        #endregion
+
+        #region Private Methods
+
+        private static byte[] compress(this byte[] data) {
+            if (data.LongLength == 0)
+                //return new byte[] { 0x00, 0x00, 0x00, 0xff, 0xff };
+                return data;
+
+            using (var input = new MemoryStream(data))
+                return input.compressToArray();
+        }
+
+        private static MemoryStream compress(this Stream stream) {
+            var output = new MemoryStream();
+            if (stream.Length == 0)
+                return output;
+
+            stream.Position = 0;
+            using (var ds = new DeflateStream(output, CompressionMode.Compress, true)) {
+                stream.CopyTo(ds, 1024);
+                ds.Close(); // BFINAL set to 1.
+                output.Write(_last, 0, 1);
+                output.Position = 0;
+
+                return output;
+            }
+        }
+
+        private static byte[] compressToArray(this Stream stream) {
+            using (var output = stream.compress()) {
+                output.Close();
+                return output.ToArray();
+            }
+        }
+
+        private static byte[] decompress(this byte[] data) {
+            if (data.LongLength == 0)
+                return data;
+
+            using (var input = new MemoryStream(data))
+                return input.decompressToArray();
+        }
+
+        private static MemoryStream decompress(this Stream stream) {
+            var output = new MemoryStream();
+            if (stream.Length == 0)
+                return output;
+
+            stream.Position = 0;
+            using (var ds = new DeflateStream(stream, CompressionMode.Decompress, true)) {
+                ds.CopyTo(output, 1024);
+                output.Position = 0;
+
+                return output;
+            }
+        }
+
+        private static byte[] decompressToArray(this Stream stream) {
+            using (var output = stream.decompress()) {
+                output.Close();
+                return output.ToArray();
+            }
+        }
+
+        private static bool isHttpMethod(this string value) {
+            return value == "GET"
+                   || value == "HEAD"
+                   || value == "POST"
+                   || value == "PUT"
+                   || value == "DELETE"
+                   || value == "CONNECT"
+                   || value == "OPTIONS"
+                   || value == "TRACE";
+        }
+
+        private static bool isHttpMethod10(this string value) {
+            return value == "GET"
+                   || value == "HEAD"
+                   || value == "POST";
+        }
+
+        #endregion
+
+        #region Internal Methods
+
+        internal static byte[] Append(this ushort code, string reason) {
+            var bytes = code.InternalToByteArray(ByteOrder.Big);
+
+            if (reason == null || reason.Length == 0)
+                return bytes;
+
+            var buff = new List<byte>(bytes);
+            buff.AddRange(Encoding.UTF8.GetBytes(reason));
+
+            return buff.ToArray();
+        }
+
+        internal static byte[] Compress(this byte[] data, CompressionMethod method) {
+            return method == CompressionMethod.Deflate
+                   ? data.compress()
+                   : data;
+        }
+
+        internal static Stream Compress(this Stream stream, CompressionMethod method) {
+            return method == CompressionMethod.Deflate
+                   ? stream.compress()
+                   : stream;
+        }
+
+        internal static byte[] CompressToArray(this Stream stream, CompressionMethod method) {
+            return method == CompressionMethod.Deflate
+                   ? stream.compressToArray()
+                   : stream.ToByteArray();
+        }
+
+        /// <summary>
+        /// Determines whether the specified string contains any of characters in
+        /// the specified array of <see cref="char"/>.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> contains any of characters in
+        /// <paramref name="anyOf"/>; otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="string"/> to test.
+        /// </param>
+        /// <param name="anyOf">
+        /// An array of <see cref="char"/> that contains one or more characters to
+        /// seek.
+        /// </param>
+        internal static bool Contains(this string value, params char[] anyOf) {
+            return anyOf != null && anyOf.Length > 0
+                   ? value.IndexOfAny(anyOf) > -1
+                   : false;
+        }
+
+        internal static bool Contains(
+          this NameValueCollection collection, string name
+        ) {
+            return collection[name] != null;
+        }
+
+        internal static bool Contains(
+          this NameValueCollection collection,
+          string name,
+          string value,
+          StringComparison comparisonTypeForValue
+        ) {
+            var val = collection[name];
+            if (val == null)
+                return false;
+
+            foreach (var elm in val.Split(',')) {
+                if (elm.Trim().Equals(value, comparisonTypeForValue))
+                    return true;
+            }
+
+            return false;
+        }
+
+        internal static bool Contains<T>(
+          this IEnumerable<T> source, Func<T, bool> condition
+        ) {
+            foreach (T elm in source) {
+                if (condition(elm))
+                    return true;
+            }
+
+            return false;
+        }
+
+        internal static bool ContainsTwice(this string[] values) {
+            var len = values.Length;
+            var end = len - 1;
+
+            Func<int, bool> seek = null;
+            seek = idx => {
+                if (idx == end)
+                    return false;
+
+                var val = values[idx];
+                for (var i = idx + 1; i < len; i++) {
+                    if (values[i] == val)
+                        return true;
+                }
+
+                return seek(++idx);
+            };
+
+            return seek(0);
+        }
+
+        internal static T[] Copy<T>(this T[] source, int length) {
+            var dest = new T[length];
+            Array.Copy(source, 0, dest, 0, length);
+
+            return dest;
+        }
+
+        internal static T[] Copy<T>(this T[] source, long length) {
+            var dest = new T[length];
+            Array.Copy(source, 0, dest, 0, length);
+
+            return dest;
+        }
+
+        internal static void CopyTo(
+          this Stream source, Stream destination, int bufferLength
+        ) {
+            var buff = new byte[bufferLength];
+            var nread = 0;
+
+            while (true) {
+                nread = source.Read(buff, 0, bufferLength);
+                if (nread <= 0)
+                    break;
+
+                destination.Write(buff, 0, nread);
+            }
+        }
+
+        internal static void CopyToAsync(
+          this Stream source,
+          Stream destination,
+          int bufferLength,
+          Action completed,
+          Action<Exception> error
+        ) {
+            var buff = new byte[bufferLength];
+
+            AsyncCallback callback = null;
+            callback =
+              ar => {
+                  try {
+                      var nread = source.EndRead(ar);
+                      if (nread <= 0) {
+                          if (completed != null)
+                              completed();
+
+                          return;
+                      }
+
+                      destination.Write(buff, 0, nread);
+                      source.BeginRead(buff, 0, bufferLength, callback, null);
+                  }
+                  catch (Exception ex) {
+                      if (error != null)
+                          error(ex);
+                  }
+              };
+
+            try {
+                source.BeginRead(buff, 0, bufferLength, callback, null);
+            }
+            catch (Exception ex) {
+                if (error != null)
+                    error(ex);
+            }
+        }
+
+        internal static byte[] Decompress(this byte[] data, CompressionMethod method) {
+            return method == CompressionMethod.Deflate
+                   ? data.decompress()
+                   : data;
+        }
+
+        internal static Stream Decompress(this Stream stream, CompressionMethod method) {
+            return method == CompressionMethod.Deflate
+                   ? stream.decompress()
+                   : stream;
+        }
+
+        internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method) {
+            return method == CompressionMethod.Deflate
+                   ? stream.decompressToArray()
+                   : stream.ToByteArray();
+        }
+
+        internal static void Emit(
+          this EventHandler eventHandler, object sender, EventArgs e
+        ) {
+            if (eventHandler == null)
+                return;
+
+            eventHandler(sender, e);
+        }
+
+        internal static void Emit<TEventArgs>(
+          this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e
+        )
+          where TEventArgs : EventArgs {
+            if (eventHandler == null)
+                return;
+
+            eventHandler(sender, e);
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="int"/> equals the specified <see cref="char"/>,
+        /// and invokes the specified <c>Action&lt;int&gt;</c> delegate at the same time.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> equals <paramref name="c"/>;
+        /// otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// An <see cref="int"/> to compare.
+        /// </param>
+        /// <param name="c">
+        /// A <see cref="char"/> to compare.
+        /// </param>
+        /// <param name="action">
+        /// An <c>Action&lt;int&gt;</c> delegate that references the method(s) called
+        /// at the same time as comparing. An <see cref="int"/> parameter to pass to
+        /// the method(s) is <paramref name="value"/>.
+        /// </param>
+        internal static bool EqualsWith(this int value, char c, Action<int> action) {
+            action(value);
+            return value == c - 0;
+        }
+
+        /// <summary>
+        /// Gets the absolute path from the specified <see cref="Uri"/>.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="string"/> that represents the absolute path if it's successfully found;
+        /// otherwise, <see langword="null"/>.
+        /// </returns>
+        /// <param name="uri">
+        /// A <see cref="Uri"/> that represents the URI to get the absolute path from.
+        /// </param>
+        internal static string GetAbsolutePath(this Uri uri) {
+            if (uri.IsAbsoluteUri)
+                return uri.AbsolutePath;
+
+            var original = uri.OriginalString;
+            if (original[0] != '/')
+                return null;
+
+            var idx = original.IndexOfAny(new[] { '?', '#' });
+            return idx > 0 ? original.Substring(0, idx) : original;
+        }
+
+        internal static CookieCollection GetCookies(
+          this NameValueCollection headers, bool response
+        ) {
+            var val = headers[response ? "Set-Cookie" : "Cookie"];
+            return val != null
+                   ? CookieCollection.Parse(val, response)
+                   : new CookieCollection();
+        }
+
+        internal static string GetDnsSafeHost(this Uri uri, bool bracketIPv6) {
+            return bracketIPv6 && uri.HostNameType == UriHostNameType.IPv6
+                   ? uri.Host
+                   : uri.DnsSafeHost;
+        }
+
+        internal static string GetMessage(this CloseStatusCode code) {
+            return code == CloseStatusCode.ProtocolError
+                   ? "A WebSocket protocol error has occurred."
+                   : code == CloseStatusCode.UnsupportedData
+                     ? "Unsupported data has been received."
+                     : code == CloseStatusCode.Abnormal
+                       ? "An exception has occurred."
+                       : code == CloseStatusCode.InvalidData
+                         ? "Invalid data has been received."
+                         : code == CloseStatusCode.PolicyViolation
+                           ? "A policy violation has occurred."
+                           : code == CloseStatusCode.TooBig
+                             ? "A too big message has been received."
+                             : code == CloseStatusCode.MandatoryExtension
+                               ? "WebSocket client didn't receive expected extension(s)."
+                               : code == CloseStatusCode.ServerError
+                                 ? "WebSocket server got an internal error."
+                                 : code == CloseStatusCode.TlsHandshakeFailure
+                                   ? "An error has occurred during a TLS handshake."
+                                   : String.Empty;
+        }
+
+        /// <summary>
+        /// Gets the name from the specified string that contains a pair of
+        /// name and value separated by a character.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A <see cref="string"/> that represents the name.
+        ///   </para>
+        ///   <para>
+        ///   <see langword="null"/> if the name is not present.
+        ///   </para>
+        /// </returns>
+        /// <param name="nameAndValue">
+        /// A <see cref="string"/> that contains a pair of name and value.
+        /// </param>
+        /// <param name="separator">
+        /// A <see cref="char"/> used to separate name and value.
+        /// </param>
+        internal static string GetName(this string nameAndValue, char separator) {
+            var idx = nameAndValue.IndexOf(separator);
+            return idx > 0 ? nameAndValue.Substring(0, idx).Trim() : null;
+        }
+
+        internal static string GetUTF8DecodedString(this byte[] bytes) {
+            return Encoding.UTF8.GetString(bytes);
+        }
+
+        internal static byte[] GetUTF8EncodedBytes(this string s) {
+            return Encoding.UTF8.GetBytes(s);
+        }
+
+        /// <summary>
+        /// Gets the value from the specified string that contains a pair of
+        /// name and value separated by a character.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A <see cref="string"/> that represents the value.
+        ///   </para>
+        ///   <para>
+        ///   <see langword="null"/> if the value is not present.
+        ///   </para>
+        /// </returns>
+        /// <param name="nameAndValue">
+        /// A <see cref="string"/> that contains a pair of name and value.
+        /// </param>
+        /// <param name="separator">
+        /// A <see cref="char"/> used to separate name and value.
+        /// </param>
+        internal static string GetValue(this string nameAndValue, char separator) {
+            return nameAndValue.GetValue(separator, false);
+        }
+
+        /// <summary>
+        /// Gets the value from the specified string that contains a pair of
+        /// name and value separated by a character.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A <see cref="string"/> that represents the value.
+        ///   </para>
+        ///   <para>
+        ///   <see langword="null"/> if the value is not present.
+        ///   </para>
+        /// </returns>
+        /// <param name="nameAndValue">
+        /// A <see cref="string"/> that contains a pair of name and value.
+        /// </param>
+        /// <param name="separator">
+        /// A <see cref="char"/> used to separate name and value.
+        /// </param>
+        /// <param name="unquote">
+        /// A <see cref="bool"/>: <c>true</c> if unquotes the value; otherwise,
+        /// <c>false</c>.
+        /// </param>
+        internal static string GetValue(
+          this string nameAndValue, char separator, bool unquote
+        ) {
+            var idx = nameAndValue.IndexOf(separator);
+            if (idx < 0 || idx == nameAndValue.Length - 1)
+                return null;
+
+            var val = nameAndValue.Substring(idx + 1).Trim();
+            return unquote ? val.Unquote() : val;
+        }
+
+        internal static byte[] InternalToByteArray(
+          this ushort value, ByteOrder order
+        ) {
+            var ret = BitConverter.GetBytes(value);
+
+            if (!order.IsHostOrder())
+                Array.Reverse(ret);
+
+            return ret;
+        }
+
+        internal static byte[] InternalToByteArray(
+          this ulong value, ByteOrder order
+        ) {
+            var ret = BitConverter.GetBytes(value);
+
+            if (!order.IsHostOrder())
+                Array.Reverse(ret);
+
+            return ret;
+        }
+
+        internal static bool IsCompressionExtension(
+          this string value, CompressionMethod method
+        ) {
+            return value.StartsWith(method.ToExtensionString());
+        }
+
+        internal static bool IsControl(this byte opcode) {
+            return opcode > 0x7 && opcode < 0x10;
+        }
+
+        internal static bool IsControl(this Opcode opcode) {
+            return opcode >= Opcode.Close;
+        }
+
+        internal static bool IsData(this byte opcode) {
+            return opcode == 0x1 || opcode == 0x2;
+        }
+
+        internal static bool IsData(this Opcode opcode) {
+            return opcode == Opcode.Text || opcode == Opcode.Binary;
+        }
+
+        internal static bool IsHttpMethod(this string value, Version version) {
+            return version == HttpVersion.Version10
+                   ? value.isHttpMethod10()
+                   : value.isHttpMethod();
+        }
+
+        internal static bool IsPortNumber(this int value) {
+            return value > 0 && value < 65536;
+        }
+
+        internal static bool IsReserved(this ushort code) {
+            return code == 1004
+                   || code == 1005
+                   || code == 1006
+                   || code == 1015;
+        }
+
+        internal static bool IsReserved(this CloseStatusCode code) {
+            return code == CloseStatusCode.Undefined
+                   || code == CloseStatusCode.NoStatus
+                   || code == CloseStatusCode.Abnormal
+                   || code == CloseStatusCode.TlsHandshakeFailure;
+        }
+
+        internal static bool IsSupported(this byte opcode) {
+            return Enum.IsDefined(typeof(Opcode), opcode);
+        }
+
+        internal static bool IsText(this string value) {
+            var len = value.Length;
+
+            for (var i = 0; i < len; i++) {
+                var c = value[i];
+                if (c < 0x20) {
+                    if ("\r\n\t".IndexOf(c) == -1)
+                        return false;
+
+                    if (c == '\n') {
+                        i++;
+                        if (i == len)
+                            break;
+
+                        c = value[i];
+                        if (" \t".IndexOf(c) == -1)
+                            return false;
+                    }
+
+                    continue;
+                }
+
+                if (c == 0x7f)
+                    return false;
+            }
+
+            return true;
+        }
+
+        internal static bool IsToken(this string value) {
+            foreach (var c in value) {
+                if (c < 0x20)
+                    return false;
+
+                if (c > 0x7e)
+                    return false;
+
+                if (_tspecials.IndexOf(c) > -1)
+                    return false;
+            }
+
+            return true;
+        }
+
+        internal static bool KeepsAlive(
+          this NameValueCollection headers, Version version
+        ) {
+            var comparison = StringComparison.OrdinalIgnoreCase;
+            return version < HttpVersion.Version11
+                   ? headers.Contains("Connection", "keep-alive", comparison)
+                   : !headers.Contains("Connection", "close", comparison);
+        }
+
+        internal static string Quote(this string value) {
+            return String.Format("\"{0}\"", value.Replace("\"", "\\\""));
+        }
+
+        internal static byte[] ReadBytes(this Stream stream, int length) {
+            var buff = new byte[length];
+            var offset = 0;
+            var retry = 0;
+            var nread = 0;
+
+            while (length > 0) {
+                nread = stream.Read(buff, offset, length);
+                if (nread <= 0) {
+                    if (retry < _retry) {
+                        retry++;
+                        continue;
+                    }
+
+                    return buff.SubArray(0, offset);
+                }
+
+                retry = 0;
+
+                offset += nread;
+                length -= nread;
+            }
+
+            return buff;
+        }
+
+        internal static byte[] ReadBytes(
+          this Stream stream, long length, int bufferLength
+        ) {
+            using (var dest = new MemoryStream()) {
+                var buff = new byte[bufferLength];
+                var retry = 0;
+                var nread = 0;
+
+                while (length > 0) {
+                    if (length < bufferLength)
+                        bufferLength = (int)length;
+
+                    nread = stream.Read(buff, 0, bufferLength);
+                    if (nread <= 0) {
+                        if (retry < _retry) {
+                            retry++;
+                            continue;
+                        }
+
+                        break;
+                    }
+
+                    retry = 0;
+
+                    dest.Write(buff, 0, nread);
+                    length -= nread;
+                }
+
+                dest.Close();
+                return dest.ToArray();
+            }
+        }
+
+        internal static void ReadBytesAsync(
+          this Stream stream,
+          int length,
+          Action<byte[]> completed,
+          Action<Exception> error
+        ) {
+            var buff = new byte[length];
+            var offset = 0;
+            var retry = 0;
+
+            AsyncCallback callback = null;
+            callback =
+              ar => {
+                  try {
+                      if (!stream.CanRead) {
+                          return;
+                      }
+                      var nread = stream.EndRead(ar);
+                      if (nread <= 0) {
+                          if (retry < _retry) {
+                              retry++;
+                              stream.BeginRead(buff, offset, length, callback, null);
+
+                              return;
+                          }
+
+                          if (completed != null)
+                              completed(buff.SubArray(0, offset));
+
+                          return;
+                      }
+
+                      if (nread == length) {
+                          if (completed != null)
+                              completed(buff);
+
+                          return;
+                      }
+
+                      retry = 0;
+
+                      offset += nread;
+                      length -= nread;
+
+                      stream.BeginRead(buff, offset, length, callback, null);
+                  }
+                  catch (Exception ex) {
+                      if (error != null)
+                          error(ex);
+                  }
+              };
+
+            try {
+                stream.BeginRead(buff, offset, length, callback, null);
+            }
+            catch (Exception ex) {
+                if (error != null)
+                    error(ex);
+            }
+        }
+
+        internal static void ReadBytesAsync(
+          this Stream stream,
+          long length,
+          int bufferLength,
+          Action<byte[]> completed,
+          Action<Exception> error
+        ) {
+            MemoryStream dest = new MemoryStream();
+            var buff = new byte[bufferLength];
+            var retry = 0;
+
+            Action<long> read = null;
+            read =
+              len => {
+                  if (len < bufferLength)
+                      bufferLength = (int)len;
+
+                  stream.BeginRead(
+                      buff,
+                      0,
+                      bufferLength,
+                      ar => {
+                          try {
+                              if (!stream.CanRead) {
+                                  dest.Close();
+                                  dest.Dispose();
+                                  return;
+                              }
+                              var nread = stream.EndRead(ar);
+                              if (nread <= 0) {
+                                  if (retry < _retry) {
+                                      retry++;
+                                      read(len);
+
+                                      return;
+                                  }
+
+                                  dest.Close();
+                                  if (completed != null) {
+                                      completed(dest.ToArray());
+                                  }
+
+                                  dest.Dispose();
+                                  return;
+                              }
+
+                              dest.Write(buff, 0, nread);
+
+                              if (nread == len) {
+                                  dest.Close();
+                                  if (completed != null) {
+                                      completed(dest.ToArray());
+                                  }
+
+                                  dest.Dispose();
+                                  return;
+                              }
+
+                              retry = 0;
+
+                              read(len - nread);
+                          }
+                          catch (Exception ex) {
+                              dest.Dispose();
+                              if (error != null)
+                                  error(ex);
+                          }
+                      },
+                      null
+                    );
+              };
+
+            try {
+                read(length);
+            }
+            catch (Exception ex) {
+                dest.Dispose();
+                if (error != null)
+                    error(ex);
+            }
+        }
+
+        internal static T[] Reverse<T>(this T[] array) {
+            var len = array.Length;
+            var ret = new T[len];
+
+            var end = len - 1;
+            for (var i = 0; i <= end; i++)
+                ret[i] = array[end - i];
+
+            return ret;
+        }
+
+        internal static IEnumerable<string> SplitHeaderValue(
+          this string value, params char[] separators
+        ) {
+            var len = value.Length;
+
+            var buff = new StringBuilder(32);
+            var end = len - 1;
+            var escaped = false;
+            var quoted = false;
+
+            for (var i = 0; i <= end; i++) {
+                var c = value[i];
+                buff.Append(c);
+
+                if (c == '"') {
+                    if (escaped) {
+                        escaped = false;
+                        continue;
+                    }
+
+                    quoted = !quoted;
+                    continue;
+                }
+
+                if (c == '\\') {
+                    if (i == end)
+                        break;
+
+                    if (value[i + 1] == '"')
+                        escaped = true;
+
+                    continue;
+                }
+
+                if (Array.IndexOf(separators, c) > -1) {
+                    if (quoted)
+                        continue;
+
+                    buff.Length -= 1;
+                    yield return buff.ToString();
+
+                    buff.Length = 0;
+                    continue;
+                }
+            }
+
+            yield return buff.ToString();
+        }
+
+        internal static byte[] ToByteArray(this Stream stream) {
+            using (var output = new MemoryStream()) {
+                stream.Position = 0;
+                stream.CopyTo(output, 1024);
+                output.Close();
+
+                return output.ToArray();
+            }
+        }
+
+        internal static CompressionMethod ToCompressionMethod(this string value) {
+            var methods = Enum.GetValues(typeof(CompressionMethod));
+            foreach (CompressionMethod method in methods) {
+                if (method.ToExtensionString() == value)
+                    return method;
+            }
+
+            return CompressionMethod.None;
+        }
+
+        internal static string ToExtensionString(
+          this CompressionMethod method, params string[] parameters
+        ) {
+            if (method == CompressionMethod.None)
+                return String.Empty;
+
+            var name = String.Format(
+                         "permessage-{0}", method.ToString().ToLower()
+                       );
+
+            return parameters != null && parameters.Length > 0
+                   ? String.Format("{0}; {1}", name, parameters.ToString("; "))
+                   : name;
+        }
+
+        internal static System.Net.IPAddress ToIPAddress(this string value) {
+            if (value == null || value.Length == 0)
+                return null;
+
+            System.Net.IPAddress addr;
+            if (System.Net.IPAddress.TryParse(value, out addr))
+                return addr;
+
+            try {
+                var addrs = System.Net.Dns.GetHostAddresses(value);
+                return addrs[0];
+            }
+            catch {
+                return null;
+            }
+        }
+
+        internal static List<TSource> ToList<TSource>(
+          this IEnumerable<TSource> source
+        ) {
+            return new List<TSource>(source);
+        }
+
+        internal static string ToString(
+          this System.Net.IPAddress address, bool bracketIPv6
+        ) {
+            return bracketIPv6
+                   && address.AddressFamily == AddressFamily.InterNetworkV6
+                   ? String.Format("[{0}]", address.ToString())
+                   : address.ToString();
+        }
+
+        internal static ushort ToUInt16(this byte[] source, ByteOrder sourceOrder) {
+            return BitConverter.ToUInt16(source.ToHostOrder(sourceOrder), 0);
+        }
+
+        internal static ulong ToUInt64(this byte[] source, ByteOrder sourceOrder) {
+            return BitConverter.ToUInt64(source.ToHostOrder(sourceOrder), 0);
+        }
+
+        internal static IEnumerable<string> TrimEach(
+          this IEnumerable<string> source
+        ) {
+            foreach (var elm in source)
+                yield return elm.Trim();
+        }
+
+        internal static string TrimSlashFromEnd(this string value) {
+            var ret = value.TrimEnd('/');
+            return ret.Length > 0 ? ret : "/";
+        }
+
+        internal static string TrimSlashOrBackslashFromEnd(this string value) {
+            var ret = value.TrimEnd('/', '\\');
+            return ret.Length > 0 ? ret : value[0].ToString();
+        }
+
+        internal static bool TryCreateVersion(
+          this string versionString, out Version result
+        ) {
+            result = null;
+
+            try {
+                result = new Version(versionString);
+            }
+            catch {
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Tries to create a new <see cref="Uri"/> for WebSocket with
+        /// the specified <paramref name="uriString"/>.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if the <see cref="Uri"/> was successfully created;
+        /// otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="uriString">
+        /// A <see cref="string"/> that represents a WebSocket URL to try.
+        /// </param>
+        /// <param name="result">
+        /// When this method returns, a <see cref="Uri"/> that
+        /// represents the WebSocket URL or <see langword="null"/>
+        /// if <paramref name="uriString"/> is invalid.
+        /// </param>
+        /// <param name="message">
+        /// When this method returns, a <see cref="string"/> that
+        /// represents an error message or <see langword="null"/>
+        /// if <paramref name="uriString"/> is valid.
+        /// </param>
+        internal static bool TryCreateWebSocketUri(
+          this string uriString, out Uri result, out string message
+        ) {
+            result = null;
+            message = null;
+
+            var uri = uriString.ToUri();
+            if (uri == null) {
+                message = "An invalid URI string.";
+                return false;
+            }
+
+            if (!uri.IsAbsoluteUri) {
+                message = "A relative URI.";
+                return false;
+            }
+
+            var schm = uri.Scheme;
+            if (!(schm == "ws" || schm == "wss")) {
+                message = "The scheme part is not 'ws' or 'wss'.";
+                return false;
+            }
+
+            var port = uri.Port;
+            if (port == 0) {
+                message = "The port part is zero.";
+                return false;
+            }
+
+            if (uri.Fragment.Length > 0) {
+                message = "It includes the fragment component.";
+                return false;
+            }
+
+            result = port != -1
+                     ? uri
+                     : new Uri(
+                         String.Format(
+                           "{0}://{1}:{2}{3}",
+                           schm,
+                           uri.Host,
+                           schm == "ws" ? 80 : 443,
+                           uri.PathAndQuery
+                         )
+                       );
+
+            return true;
+        }
+
+        internal static bool TryGetUTF8DecodedString(this byte[] bytes, out string s) {
+            s = null;
+
+            try {
+                s = Encoding.UTF8.GetString(bytes);
+            }
+            catch {
+                return false;
+            }
+
+            return true;
+        }
+
+        internal static bool TryGetUTF8EncodedBytes(this string s, out byte[] bytes) {
+            bytes = null;
+
+            try {
+                bytes = Encoding.UTF8.GetBytes(s);
+            }
+            catch {
+                return false;
+            }
+
+            return true;
+        }
+
+        internal static bool TryOpenRead(
+          this FileInfo fileInfo, out FileStream fileStream
+        ) {
+            fileStream = null;
+
+            try {
+                fileStream = fileInfo.OpenRead();
+            }
+            catch {
+                return false;
+            }
+
+            return true;
+        }
+
+        internal static string Unquote(this string value) {
+            var start = value.IndexOf('"');
+            if (start == -1)
+                return value;
+
+            var end = value.LastIndexOf('"');
+            if (end == start)
+                return value;
+
+            var len = end - start - 1;
+            return len > 0
+                   ? value.Substring(start + 1, len).Replace("\\\"", "\"")
+                   : String.Empty;
+        }
+
+        internal static bool Upgrades(
+          this NameValueCollection headers, string protocol
+        ) {
+            var comparison = StringComparison.OrdinalIgnoreCase;
+            return headers.Contains("Upgrade", protocol, comparison)
+                   && headers.Contains("Connection", "Upgrade", comparison);
+        }
+
+        internal static string UrlDecode(this string value, Encoding encoding) {
+            return HttpUtility.UrlDecode(value, encoding);
+        }
+
+        internal static string UrlEncode(this string value, Encoding encoding) {
+            return HttpUtility.UrlEncode(value, encoding);
+        }
+
+        internal static void WriteBytes(
+          this Stream stream, byte[] bytes, int bufferLength
+        ) {
+            using (var src = new MemoryStream(bytes))
+                src.CopyTo(stream, bufferLength);
+        }
+
+        internal static void WriteBytesAsync(
+          this Stream stream,
+          byte[] bytes,
+          int bufferLength,
+          Action completed,
+          Action<Exception> error
+        ) {
+            var src = new MemoryStream(bytes);
+            src.CopyToAsync(
+              stream,
+              bufferLength,
+              () => {
+                  if (completed != null)
+                      completed();
+
+                  src.Dispose();
+              },
+              ex => {
+                  src.Dispose();
+                  if (error != null)
+                      error(ex);
+              }
+            );
+        }
+
+        #endregion
+
+        #region Public Methods
+
+        /// <summary>
+        /// Gets the description of the specified HTTP status code.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="string"/> that represents the description of
+        /// the HTTP status code.
+        /// </returns>
+        /// <param name="code">
+        ///   <para>
+        ///   One of the <see cref="HttpStatusCode"/> enum values.
+        ///   </para>
+        ///   <para>
+        ///   It specifies the HTTP status code.
+        ///   </para>
+        /// </param>
+        public static string GetDescription(this HttpStatusCode code) {
+            return ((int)code).GetStatusDescription();
+        }
+
+        /// <summary>
+        /// Gets the description of the specified HTTP status code.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A <see cref="string"/> that represents the description of
+        ///   the HTTP status code.
+        ///   </para>
+        ///   <para>
+        ///   An empty string if the description is not present.
+        ///   </para>
+        /// </returns>
+        /// <param name="code">
+        /// An <see cref="int"/> that specifies the HTTP status code.
+        /// </param>
+        public static string GetStatusDescription(this int code) {
+            switch (code) {
+                case 100: return "Continue";
+                case 101: return "Switching Protocols";
+                case 102: return "Processing";
+                case 200: return "OK";
+                case 201: return "Created";
+                case 202: return "Accepted";
+                case 203: return "Non-Authoritative Information";
+                case 204: return "No Content";
+                case 205: return "Reset Content";
+                case 206: return "Partial Content";
+                case 207: return "Multi-Status";
+                case 300: return "Multiple Choices";
+                case 301: return "Moved Permanently";
+                case 302: return "Found";
+                case 303: return "See Other";
+                case 304: return "Not Modified";
+                case 305: return "Use Proxy";
+                case 307: return "Temporary Redirect";
+                case 400: return "Bad Request";
+                case 401: return "Unauthorized";
+                case 402: return "Payment Required";
+                case 403: return "Forbidden";
+                case 404: return "Not Found";
+                case 405: return "Method Not Allowed";
+                case 406: return "Not Acceptable";
+                case 407: return "Proxy Authentication Required";
+                case 408: return "Request Timeout";
+                case 409: return "Conflict";
+                case 410: return "Gone";
+                case 411: return "Length Required";
+                case 412: return "Precondition Failed";
+                case 413: return "Request Entity Too Large";
+                case 414: return "Request-Uri Too Long";
+                case 415: return "Unsupported Media Type";
+                case 416: return "Requested Range Not Satisfiable";
+                case 417: return "Expectation Failed";
+                case 422: return "Unprocessable Entity";
+                case 423: return "Locked";
+                case 424: return "Failed Dependency";
+                case 500: return "Internal Server Error";
+                case 501: return "Not Implemented";
+                case 502: return "Bad Gateway";
+                case 503: return "Service Unavailable";
+                case 504: return "Gateway Timeout";
+                case 505: return "Http Version Not Supported";
+                case 507: return "Insufficient Storage";
+            }
+
+            return String.Empty;
+        }
+
+        /// <summary>
+        /// Determines whether the specified ushort is in the range of
+        /// the status code for the WebSocket connection close.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///   The ranges are the following:
+        ///   </para>
+        ///   <list type="bullet">
+        ///     <item>
+        ///       <term>
+        ///       1000-2999: These numbers are reserved for definition by
+        ///       the WebSocket protocol.
+        ///       </term>
+        ///     </item>
+        ///     <item>
+        ///       <term>
+        ///       3000-3999: These numbers are reserved for use by libraries,
+        ///       frameworks, and applications.
+        ///       </term>
+        ///     </item>
+        ///     <item>
+        ///       <term>
+        ///       4000-4999: These numbers are reserved for private use.
+        ///       </term>
+        ///     </item>
+        ///   </list>
+        /// </remarks>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> is in the range of
+        /// the status code for the close; otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="ushort"/> to test.
+        /// </param>
+        public static bool IsCloseStatusCode(this ushort value) {
+            return value > 999 && value < 5000;
+        }
+
+        /// <summary>
+        /// Determines whether the specified string is enclosed in
+        /// the specified character.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> is enclosed in
+        /// <paramref name="c"/>; otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="string"/> to test.
+        /// </param>
+        /// <param name="c">
+        /// A <see cref="char"/> to find.
+        /// </param>
+        public static bool IsEnclosedIn(this string value, char c) {
+            if (value == null)
+                return false;
+
+            var len = value.Length;
+            if (len < 2)
+                return false;
+
+            return value[0] == c && value[len - 1] == c;
+        }
+
+        /// <summary>
+        /// Determines whether the specified byte order is host (this computer
+        /// architecture) byte order.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="order"/> is host byte order; otherwise,
+        /// <c>false</c>.
+        /// </returns>
+        /// <param name="order">
+        /// One of the <see cref="ByteOrder"/> enum values to test.
+        /// </param>
+        public static bool IsHostOrder(this ByteOrder order) {
+            // true: !(true ^ true) or !(false ^ false)
+            // false: !(true ^ false) or !(false ^ true)
+            return !(BitConverter.IsLittleEndian ^ (order == ByteOrder.Little));
+        }
+
+        /// <summary>
+        /// Determines whether the specified IP address is a local IP address.
+        /// </summary>
+        /// <remarks>
+        /// This local means NOT REMOTE for the current host.
+        /// </remarks>
+        /// <returns>
+        /// <c>true</c> if <paramref name="address"/> is a local IP address;
+        /// otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="address">
+        /// A <see cref="System.Net.IPAddress"/> to test.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="address"/> is <see langword="null"/>.
+        /// </exception>
+        public static bool IsLocal(this System.Net.IPAddress address) {
+            if (address == null)
+                throw new ArgumentNullException("address");
+
+            if (address.Equals(System.Net.IPAddress.Any))
+                return true;
+
+            if (address.Equals(System.Net.IPAddress.Loopback))
+                return true;
+
+            if (Socket.OSSupportsIPv6) {
+                if (address.Equals(System.Net.IPAddress.IPv6Any))
+                    return true;
+
+                if (address.Equals(System.Net.IPAddress.IPv6Loopback))
+                    return true;
+            }
+
+            var host = System.Net.Dns.GetHostName();
+            var addrs = System.Net.Dns.GetHostAddresses(host);
+            foreach (var addr in addrs) {
+                if (address.Equals(addr))
+                    return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Determines whether the specified string is <see langword="null"/> or
+        /// an empty string.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> is <see langword="null"/> or
+        /// an empty string; otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="string"/> to test.
+        /// </param>
+        public static bool IsNullOrEmpty(this string value) {
+            return value == null || value.Length == 0;
+        }
+
+        /// <summary>
+        /// Determines whether the specified string is a predefined scheme.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> is a predefined scheme;
+        /// otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="string"/> to test.
+        /// </param>
+        public static bool IsPredefinedScheme(this string value) {
+            if (value == null || value.Length < 2)
+                return false;
+
+            var c = value[0];
+            if (c == 'h')
+                return value == "http" || value == "https";
+
+            if (c == 'w')
+                return value == "ws" || value == "wss";
+
+            if (c == 'f')
+                return value == "file" || value == "ftp";
+
+            if (c == 'g')
+                return value == "gopher";
+
+            if (c == 'm')
+                return value == "mailto";
+
+            if (c == 'n') {
+                c = value[1];
+                return c == 'e'
+                       ? value == "news" || value == "net.pipe" || value == "net.tcp"
+                       : value == "nntp";
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Determines whether the specified string is a URI string.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if <paramref name="value"/> may be a URI string;
+        /// otherwise, <c>false</c>.
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="string"/> to test.
+        /// </param>
+        public static bool MaybeUri(this string value) {
+            if (value == null)
+                return false;
+
+            if (value.Length == 0)
+                return false;
+
+            var idx = value.IndexOf(':');
+            if (idx == -1)
+                return false;
+
+            if (idx >= 10)
+                return false;
+
+            var schm = value.Substring(0, idx);
+            return schm.IsPredefinedScheme();
+        }
+
+        /// <summary>
+        /// Retrieves a sub-array from the specified array. A sub-array starts at
+        /// the specified index in the array.
+        /// </summary>
+        /// <returns>
+        /// An array of T that receives a sub-array.
+        /// </returns>
+        /// <param name="array">
+        /// An array of T from which to retrieve a sub-array.
+        /// </param>
+        /// <param name="startIndex">
+        /// An <see cref="int"/> that represents the zero-based index in the array
+        /// at which retrieving starts.
+        /// </param>
+        /// <param name="length">
+        /// An <see cref="int"/> that represents the number of elements to retrieve.
+        /// </param>
+        /// <typeparam name="T">
+        /// The type of elements in the array.
+        /// </typeparam>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="array"/> is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <para>
+        ///   <paramref name="startIndex"/> is less than zero.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="startIndex"/> is greater than the end of the array.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="length"/> is less than zero.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="length"/> is greater than the number of elements from
+        ///   <paramref name="startIndex"/> to the end of the array.
+        ///   </para>
+        /// </exception>
+        public static T[] SubArray<T>(this T[] array, int startIndex, int length) {
+            if (array == null)
+                throw new ArgumentNullException("array");
+
+            var len = array.Length;
+            if (len == 0) {
+                if (startIndex != 0)
+                    throw new ArgumentOutOfRangeException("startIndex");
+
+                if (length != 0)
+                    throw new ArgumentOutOfRangeException("length");
+
+                return array;
+            }
+
+            if (startIndex < 0 || startIndex >= len)
+                throw new ArgumentOutOfRangeException("startIndex");
+
+            if (length < 0 || length > len - startIndex)
+                throw new ArgumentOutOfRangeException("length");
+
+            if (length == 0)
+                return new T[0];
+
+            if (length == len)
+                return array;
+
+            var subArray = new T[length];
+            Array.Copy(array, startIndex, subArray, 0, length);
+
+            return subArray;
+        }
+
+        /// <summary>
+        /// Retrieves a sub-array from the specified array. A sub-array starts at
+        /// the specified index in the array.
+        /// </summary>
+        /// <returns>
+        /// An array of T that receives a sub-array.
+        /// </returns>
+        /// <param name="array">
+        /// An array of T from which to retrieve a sub-array.
+        /// </param>
+        /// <param name="startIndex">
+        /// A <see cref="long"/> that represents the zero-based index in the array
+        /// at which retrieving starts.
+        /// </param>
+        /// <param name="length">
+        /// A <see cref="long"/> that represents the number of elements to retrieve.
+        /// </param>
+        /// <typeparam name="T">
+        /// The type of elements in the array.
+        /// </typeparam>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="array"/> is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <para>
+        ///   <paramref name="startIndex"/> is less than zero.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="startIndex"/> is greater than the end of the array.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="length"/> is less than zero.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="length"/> is greater than the number of elements from
+        ///   <paramref name="startIndex"/> to the end of the array.
+        ///   </para>
+        /// </exception>
+        public static T[] SubArray<T>(this T[] array, long startIndex, long length) {
+            if (array == null)
+                throw new ArgumentNullException("array");
+
+            var len = array.LongLength;
+            if (len == 0) {
+                if (startIndex != 0)
+                    throw new ArgumentOutOfRangeException("startIndex");
+
+                if (length != 0)
+                    throw new ArgumentOutOfRangeException("length");
+
+                return array;
+            }
+
+            if (startIndex < 0 || startIndex >= len)
+                throw new ArgumentOutOfRangeException("startIndex");
+
+            if (length < 0 || length > len - startIndex)
+                throw new ArgumentOutOfRangeException("length");
+
+            if (length == 0)
+                return new T[0];
+
+            if (length == len)
+                return array;
+
+            var subArray = new T[length];
+            Array.Copy(array, startIndex, subArray, 0, length);
+
+            return subArray;
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// An <see cref="int"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        /// An <see cref="Action"/> delegate to execute.
+        /// </param>
+        public static void Times(this int n, Action action) {
+            if (n <= 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (int i = 0; i < n; i++)
+                action();
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// A <see cref="long"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        /// An <see cref="Action"/> delegate to execute.
+        /// </param>
+        public static void Times(this long n, Action action) {
+            if (n <= 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (long i = 0; i < n; i++)
+                action();
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// A <see cref="uint"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        /// An <see cref="Action"/> delegate to execute.
+        /// </param>
+        public static void Times(this uint n, Action action) {
+            if (n == 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (uint i = 0; i < n; i++)
+                action();
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// A <see cref="ulong"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        /// An <see cref="Action"/> delegate to execute.
+        /// </param>
+        public static void Times(this ulong n, Action action) {
+            if (n == 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (ulong i = 0; i < n; i++)
+                action();
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// An <see cref="int"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        ///   <para>
+        ///   An <c>Action&lt;int&gt;</c> delegate to execute.
+        ///   </para>
+        ///   <para>
+        ///   The <see cref="int"/> parameter is the zero-based count of iteration.
+        ///   </para>
+        /// </param>
+        public static void Times(this int n, Action<int> action) {
+            if (n <= 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (int i = 0; i < n; i++)
+                action(i);
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// A <see cref="long"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        ///   <para>
+        ///   An <c>Action&lt;long&gt;</c> delegate to execute.
+        ///   </para>
+        ///   <para>
+        ///   The <see cref="long"/> parameter is the zero-based count of iteration.
+        ///   </para>
+        /// </param>
+        public static void Times(this long n, Action<long> action) {
+            if (n <= 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (long i = 0; i < n; i++)
+                action(i);
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// A <see cref="uint"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        ///   <para>
+        ///   An <c>Action&lt;uint&gt;</c> delegate to execute.
+        ///   </para>
+        ///   <para>
+        ///   The <see cref="uint"/> parameter is the zero-based count of iteration.
+        ///   </para>
+        /// </param>
+        public static void Times(this uint n, Action<uint> action) {
+            if (n == 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (uint i = 0; i < n; i++)
+                action(i);
+        }
+
+        /// <summary>
+        /// Executes the specified delegate <paramref name="n"/> times.
+        /// </summary>
+        /// <param name="n">
+        /// A <see cref="ulong"/> that specifies the number of times to execute.
+        /// </param>
+        /// <param name="action">
+        ///   <para>
+        ///   An <c>Action&lt;ulong&gt;</c> delegate to execute.
+        ///   </para>
+        ///   <para>
+        ///   The <see cref="ulong"/> parameter is the zero-based count of iteration.
+        ///   </para>
+        /// </param>
+        public static void Times(this ulong n, Action<ulong> action) {
+            if (n == 0)
+                return;
+
+            if (action == null)
+                return;
+
+            for (ulong i = 0; i < n; i++)
+                action(i);
+        }
+
+        /// <summary>
+        /// Converts the specified byte array to the specified type value.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A T converted from <paramref name="source"/>.
+        ///   </para>
+        ///   <para>
+        ///   The default value of T if not converted.
+        ///   </para>
+        /// </returns>
+        /// <param name="source">
+        /// An array of <see cref="byte"/> to convert.
+        /// </param>
+        /// <param name="sourceOrder">
+        ///   <para>
+        ///   One of the <see cref="ByteOrder"/> enum values.
+        ///   </para>
+        ///   <para>
+        ///   It specifies the byte order of <paramref name="source"/>.
+        ///   </para>
+        /// </param>
+        /// <typeparam name="T">
+        ///   <para>
+        ///   The type of the return.
+        ///   </para>
+        ///   <para>
+        ///   <see cref="bool"/>, <see cref="char"/>, <see cref="double"/>,
+        ///   <see cref="float"/>, <see cref="int"/>, <see cref="long"/>,
+        ///   <see cref="short"/>, <see cref="uint"/>, <see cref="ulong"/>,
+        ///   or <see cref="ushort"/>.
+        ///   </para>
+        /// </typeparam>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="source"/> is <see langword="null"/>.
+        /// </exception>
+        [Obsolete("This method will be removed.")]
+        public static T To<T>(this byte[] source, ByteOrder sourceOrder)
+          where T : struct {
+            if (source == null)
+                throw new ArgumentNullException("source");
+
+            if (source.Length == 0)
+                return default(T);
+
+            var type = typeof(T);
+            var val = source.ToHostOrder(sourceOrder);
+
+            return type == typeof(Boolean)
+                   ? (T)(object)BitConverter.ToBoolean(val, 0)
+                   : type == typeof(Char)
+                     ? (T)(object)BitConverter.ToChar(val, 0)
+                     : type == typeof(Double)
+                       ? (T)(object)BitConverter.ToDouble(val, 0)
+                       : type == typeof(Int16)
+                         ? (T)(object)BitConverter.ToInt16(val, 0)
+                         : type == typeof(Int32)
+                           ? (T)(object)BitConverter.ToInt32(val, 0)
+                           : type == typeof(Int64)
+                             ? (T)(object)BitConverter.ToInt64(val, 0)
+                             : type == typeof(Single)
+                               ? (T)(object)BitConverter.ToSingle(val, 0)
+                               : type == typeof(UInt16)
+                                 ? (T)(object)BitConverter.ToUInt16(val, 0)
+                                 : type == typeof(UInt32)
+                                   ? (T)(object)BitConverter.ToUInt32(val, 0)
+                                   : type == typeof(UInt64)
+                                     ? (T)(object)BitConverter.ToUInt64(val, 0)
+                                     : default(T);
+        }
+
+        /// <summary>
+        /// Converts the specified value to a byte array.
+        /// </summary>
+        /// <returns>
+        /// An array of <see cref="byte"/> converted from <paramref name="value"/>.
+        /// </returns>
+        /// <param name="value">
+        /// A T to convert.
+        /// </param>
+        /// <param name="order">
+        ///   <para>
+        ///   One of the <see cref="ByteOrder"/> enum values.
+        ///   </para>
+        ///   <para>
+        ///   It specifies the byte order of the return.
+        ///   </para>
+        /// </param>
+        /// <typeparam name="T">
+        ///   <para>
+        ///   The type of <paramref name="value"/>.
+        ///   </para>
+        ///   <para>
+        ///   <see cref="bool"/>, <see cref="byte"/>, <see cref="char"/>,
+        ///   <see cref="double"/>, <see cref="float"/>, <see cref="int"/>,
+        ///   <see cref="long"/>, <see cref="short"/>, <see cref="uint"/>,
+        ///   <see cref="ulong"/>, or <see cref="ushort"/>.
+        ///   </para>
+        /// </typeparam>
+        [Obsolete("This method will be removed.")]
+        public static byte[] ToByteArray<T>(this T value, ByteOrder order)
+          where T : struct {
+            var type = typeof(T);
+            var bytes = type == typeof(Boolean)
+                        ? BitConverter.GetBytes((Boolean)(object)value)
+                        : type == typeof(Byte)
+                          ? new byte[] { (Byte)(object)value }
+                          : type == typeof(Char)
+                            ? BitConverter.GetBytes((Char)(object)value)
+                            : type == typeof(Double)
+                              ? BitConverter.GetBytes((Double)(object)value)
+                              : type == typeof(Int16)
+                                ? BitConverter.GetBytes((Int16)(object)value)
+                                : type == typeof(Int32)
+                                  ? BitConverter.GetBytes((Int32)(object)value)
+                                  : type == typeof(Int64)
+                                    ? BitConverter.GetBytes((Int64)(object)value)
+                                    : type == typeof(Single)
+                                      ? BitConverter.GetBytes((Single)(object)value)
+                                      : type == typeof(UInt16)
+                                        ? BitConverter.GetBytes((UInt16)(object)value)
+                                        : type == typeof(UInt32)
+                                          ? BitConverter.GetBytes((UInt32)(object)value)
+                                          : type == typeof(UInt64)
+                                            ? BitConverter.GetBytes((UInt64)(object)value)
+                                            : WebSocket.EmptyBytes;
+
+            if (bytes.Length > 1) {
+                if (!order.IsHostOrder())
+                    Array.Reverse(bytes);
+            }
+
+            return bytes;
+        }
+
+        /// <summary>
+        /// Converts the order of elements in the specified byte array to
+        /// host (this computer architecture) byte order.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   An array of <see cref="byte"/> converted from
+        ///   <paramref name="source"/>.
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="source"/> if the number of elements in
+        ///   it is less than 2 or <paramref name="sourceOrder"/> is
+        ///   same as host byte order.
+        ///   </para>
+        /// </returns>
+        /// <param name="source">
+        /// An array of <see cref="byte"/> to convert.
+        /// </param>
+        /// <param name="sourceOrder">
+        ///   <para>
+        ///   One of the <see cref="ByteOrder"/> enum values.
+        ///   </para>
+        ///   <para>
+        ///   It specifies the order of elements in <paramref name="source"/>.
+        ///   </para>
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="source"/> is <see langword="null"/>.
+        /// </exception>
+        public static byte[] ToHostOrder(this byte[] source, ByteOrder sourceOrder) {
+            if (source == null)
+                throw new ArgumentNullException("source");
+
+            if (source.Length < 2)
+                return source;
+
+            if (sourceOrder.IsHostOrder())
+                return source;
+
+            return source.Reverse();
+        }
+
+        /// <summary>
+        /// Converts the specified array to a string.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A <see cref="string"/> converted by concatenating each element of
+        ///   <paramref name="array"/> across <paramref name="separator"/>.
+        ///   </para>
+        ///   <para>
+        ///   An empty string if <paramref name="array"/> is an empty array.
+        ///   </para>
+        /// </returns>
+        /// <param name="array">
+        /// An array of T to convert.
+        /// </param>
+        /// <param name="separator">
+        /// A <see cref="string"/> used to separate each element of
+        /// <paramref name="array"/>.
+        /// </param>
+        /// <typeparam name="T">
+        /// The type of elements in <paramref name="array"/>.
+        /// </typeparam>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="array"/> is <see langword="null"/>.
+        /// </exception>
+        public static string ToString<T>(this T[] array, string separator) {
+            if (array == null)
+                throw new ArgumentNullException("array");
+
+            var len = array.Length;
+            if (len == 0)
+                return String.Empty;
+
+            if (separator == null)
+                separator = String.Empty;
+
+            var buff = new StringBuilder(64);
+            var end = len - 1;
+
+            for (var i = 0; i < end; i++)
+                buff.AppendFormat("{0}{1}", array[i], separator);
+
+            buff.Append(array[end].ToString());
+            return buff.ToString();
+        }
+
+        /// <summary>
+        /// Converts the specified string to a <see cref="Uri"/>.
+        /// </summary>
+        /// <returns>
+        ///   <para>
+        ///   A <see cref="Uri"/> converted from <paramref name="value"/>.
+        ///   </para>
+        ///   <para>
+        ///   <see langword="null"/> if the conversion has failed.
+        ///   </para>
+        /// </returns>
+        /// <param name="value">
+        /// A <see cref="string"/> to convert.
+        /// </param>
+        public static Uri ToUri(this string value) {
+            Uri ret;
+            Uri.TryCreate(
+              value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out ret
+            );
+
+            return ret;
+        }
+
+        /// <summary>
+        /// Sends the specified content data with the HTTP response.
+        /// </summary>
+        /// <param name="response">
+        /// A <see cref="HttpListenerResponse"/> that represents the HTTP response
+        /// used to send the content data.
+        /// </param>
+        /// <param name="content">
+        /// An array of <see cref="byte"/> that specifies the content data to send.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        ///   <para>
+        ///   <paramref name="response"/> is <see langword="null"/>.
+        ///   </para>
+        ///   <para>
+        ///   -or-
+        ///   </para>
+        ///   <para>
+        ///   <paramref name="content"/> is <see langword="null"/>.
+        ///   </para>
+        /// </exception>
+        [Obsolete("This method will be removed.")]
+        public static void WriteContent(
+          this HttpListenerResponse response, byte[] content
+        ) {
+            if (response == null)
+                throw new ArgumentNullException("response");
+
+            if (content == null)
+                throw new ArgumentNullException("content");
+
+            var len = content.LongLength;
+            if (len == 0) {
+                response.Close();
+                return;
+            }
+
+            response.ContentLength64 = len;
+
+            var output = response.OutputStream;
+
+            if (len <= Int32.MaxValue)
+                output.Write(content, 0, (int)len);
+            else
+                output.WriteBytes(content, 1024);
+
+            output.Close();
+        }
+
+        #endregion
+    }
+}

+ 51 - 0
src/websocket-sharp/Fin.cs

@@ -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 - 0
src/websocket-sharp/HttpBase.cs

@@ -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 - 0
src/websocket-sharp/HttpRequest.cs

@@ -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 - 0
src/websocket-sharp/HttpResponse.cs

@@ -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 - 0
src/websocket-sharp/LogData.cs

@@ -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 - 0
src/websocket-sharp/LogLevel.cs

@@ -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 - 0
src/websocket-sharp/Logger.cs

@@ -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&lt;LogData, string&gt;</c>
+  ///   delegate.
+  ///   </para>
+  /// </remarks>
+  public class Logger
+  {
+    #region Private Fields
+
+    private volatile string         _file;
+    private volatile LogLevel       _level;
+    private Action<LogData, string> _output;
+    private object                  _sync;
+
+    #endregion
+
+    #region Public Constructors
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Logger"/> class.
+    /// </summary>
+    /// <remarks>
+    /// This constructor initializes the current logging level with <see cref="LogLevel.Error"/>.
+    /// </remarks>
+    public Logger ()
+      : this (LogLevel.Error, null, null)
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Logger"/> class with
+    /// the specified logging <paramref name="level"/>.
+    /// </summary>
+    /// <param name="level">
+    /// One of the <see cref="LogLevel"/> enum values.
+    /// </param>
+    public Logger (LogLevel level)
+      : this (level, null, null)
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Logger"/> class with
+    /// the specified logging <paramref name="level"/>, path to the log <paramref name="file"/>,
+    /// and <paramref name="output"/> action.
+    /// </summary>
+    /// <param name="level">
+    /// One of the <see cref="LogLevel"/> enum values.
+    /// </param>
+    /// <param name="file">
+    /// A <see cref="string"/> that represents the path to the log file.
+    /// </param>
+    /// <param name="output">
+    /// An <c>Action&lt;LogData, string&gt;</c> delegate that references the method(s) used to
+    /// output a log. A <see cref="string"/> parameter passed to this delegate is
+    /// <paramref name="file"/>.
+    /// </param>
+    public Logger (LogLevel level, string file, Action<LogData, string> output)
+    {
+      _level = level;
+      _file = file;
+      _output = output ?? defaultOutput;
+      _sync = new object ();
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    /// <summary>
+    /// Gets or sets the current path to the log file.
+    /// </summary>
+    /// <value>
+    /// A <see cref="string"/> that represents the current path to the log file if any.
+    /// </value>
+    public string File {
+      get {
+        return _file;
+      }
+
+      set {
+        lock (_sync) {
+          _file = value;
+          Warn (
+            String.Format ("The current path to the log file has been changed to {0}.", _file));
+        }
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the current logging level.
+    /// </summary>
+    /// <remarks>
+    /// A log with lower than the value of this property cannot be outputted.
+    /// </remarks>
+    /// <value>
+    /// One of the <see cref="LogLevel"/> enum values, specifies the current logging level.
+    /// </value>
+    public LogLevel Level {
+      get {
+        return _level;
+      }
+
+      set {
+        lock (_sync) {
+          _level = value;
+          Warn (String.Format ("The current logging level has been changed to {0}.", _level));
+        }
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the current output action used to output a log.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   An <c>Action&lt;LogData, string&gt;</c> delegate that references the method(s) used to
+    ///   output a log. A <see cref="string"/> parameter passed to this delegate is the value of
+    ///   the <see cref="Logger.File"/> property.
+    ///   </para>
+    ///   <para>
+    ///   If the value to set is <see langword="null"/>, the current output action is changed to
+    ///   the default output action.
+    ///   </para>
+    /// </value>
+    public Action<LogData, string> Output {
+      get {
+        return _output;
+      }
+
+      set {
+        lock (_sync) {
+          _output = value ?? defaultOutput;
+          Warn ("The current output action has been changed.");
+        }
+      }
+    }
+
+    #endregion
+
+    #region Private Methods
+
+    private static void defaultOutput (LogData data, string path)
+    {
+      var log = data.ToString ();
+      Console.WriteLine (log);
+      if (path != null && path.Length > 0)
+        writeToFile (log, path);
+    }
+
+    private void output (string message, LogLevel level)
+    {
+      lock (_sync) {
+        if (_level > level)
+          return;
+
+        LogData data = null;
+        try {
+          data = new LogData (level, new StackFrame (2, true), message);
+          _output (data, _file);
+        }
+        catch (Exception ex) {
+          data = new LogData (LogLevel.Fatal, new StackFrame (0, true), ex.Message);
+          Console.WriteLine (data.ToString ());
+        }
+      }
+    }
+
+    private static void writeToFile (string value, string path)
+    {
+      using (var writer = new StreamWriter (path, true))
+      using (var syncWriter = TextWriter.Synchronized (writer))
+        syncWriter.WriteLine (value);
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    /// <summary>
+    /// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Debug"/>.
+    /// </summary>
+    /// <remarks>
+    /// If the current logging level is higher than <see cref="LogLevel.Debug"/>,
+    /// this method doesn't output <paramref name="message"/> as a log.
+    /// </remarks>
+    /// <param name="message">
+    /// A <see cref="string"/> that represents the message to output as a log.
+    /// </param>
+    public void Debug (string message)
+    {
+      if (_level > LogLevel.Debug)
+        return;
+
+      output (message, LogLevel.Debug);
+    }
+
+    /// <summary>
+    /// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Error"/>.
+    /// </summary>
+    /// <remarks>
+    /// If the current logging level is higher than <see cref="LogLevel.Error"/>,
+    /// this method doesn't output <paramref name="message"/> as a log.
+    /// </remarks>
+    /// <param name="message">
+    /// A <see cref="string"/> that represents the message to output as a log.
+    /// </param>
+    public void Error (string message)
+    {
+      if (_level > LogLevel.Error)
+        return;
+
+      output (message, LogLevel.Error);
+    }
+
+    /// <summary>
+    /// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Fatal"/>.
+    /// </summary>
+    /// <param name="message">
+    /// A <see cref="string"/> that represents the message to output as a log.
+    /// </param>
+    public void Fatal (string message)
+    {
+      output (message, LogLevel.Fatal);
+    }
+
+    /// <summary>
+    /// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Info"/>.
+    /// </summary>
+    /// <remarks>
+    /// If the current logging level is higher than <see cref="LogLevel.Info"/>,
+    /// this method doesn't output <paramref name="message"/> as a log.
+    /// </remarks>
+    /// <param name="message">
+    /// A <see cref="string"/> that represents the message to output as a log.
+    /// </param>
+    public void Info (string message)
+    {
+      if (_level > LogLevel.Info)
+        return;
+
+      output (message, LogLevel.Info);
+    }
+
+    /// <summary>
+    /// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Trace"/>.
+    /// </summary>
+    /// <remarks>
+    /// If the current logging level is higher than <see cref="LogLevel.Trace"/>,
+    /// this method doesn't output <paramref name="message"/> as a log.
+    /// </remarks>
+    /// <param name="message">
+    /// A <see cref="string"/> that represents the message to output as a log.
+    /// </param>
+    public void Trace (string message)
+    {
+      if (_level > LogLevel.Trace)
+        return;
+
+      output (message, LogLevel.Trace);
+    }
+
+    /// <summary>
+    /// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Warn"/>.
+    /// </summary>
+    /// <remarks>
+    /// If the current logging level is higher than <see cref="LogLevel.Warn"/>,
+    /// this method doesn't output <paramref name="message"/> as a log.
+    /// </remarks>
+    /// <param name="message">
+    /// A <see cref="string"/> that represents the message to output as a log.
+    /// </param>
+    public void Warn (string message)
+    {
+      if (_level > LogLevel.Warn)
+        return;
+
+      output (message, LogLevel.Warn);
+    }
+
+    #endregion
+  }
+}

+ 51 - 0
src/websocket-sharp/Mask.cs

@@ -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 - 0
src/websocket-sharp/MessageEventArgs.cs

@@ -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 - 0
src/websocket-sharp/Net/AuthenticationBase.cs

@@ -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 - 0
src/websocket-sharp/Net/AuthenticationChallenge.cs

@@ -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 - 0
src/websocket-sharp/Net/AuthenticationResponse.cs

@@ -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 - 0
src/websocket-sharp/Net/AuthenticationSchemes.cs

@@ -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 <[email protected]>
+ */
+#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 - 0
src/websocket-sharp/Net/Chunk.cs

@@ -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 <[email protected]>
+ */
+#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 - 0
src/websocket-sharp/Net/ChunkStream.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 213 - 0
src/websocket-sharp/Net/ChunkedRequestStream.cs

@@ -0,0 +1,213 @@
+#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 <[email protected]>
+ */
+#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.ErrorMessage = ex.Message;
+        _context.SendError ();
+
+        ares.Complete (ex);
+      }
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    public override IAsyncResult BeginRead (
+      byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+    {
+      if (_disposed)
+        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
+  }
+}

+ 303 - 0
src/websocket-sharp/Net/ClientSslConfiguration.cs

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

+ 1016 - 0
src/websocket-sharp/Net/Cookie.cs

@@ -0,0 +1,1016 @@
+#region License
+/*
+ * Cookie.cs
+ *
+ * This code is derived from Cookie.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 <[email protected]>
+ * - Gonzalo Paniagua Javier <[email protected]>
+ * - Daniel Nauck <[email protected]>
+ * - Sebastien Pouliot <[email protected]>
+ */
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text;
+
+namespace WebSocketSharp.Net
+{
+  /// <summary>
+  /// Provides a set of methods and properties used to manage an HTTP cookie.
+  /// </summary>
+  /// <remarks>
+  ///   <para>
+  ///   This class refers to the following specifications:
+  ///   </para>
+  ///   <list type="bullet">
+  ///     <item>
+  ///       <term>
+  ///       <see href="http://web.archive.org/web/20020803110822/http://wp.netscape.com/newsref/std/cookie_spec.html">Netscape specification</see>
+  ///       </term>
+  ///     </item>
+  ///     <item>
+  ///       <term>
+  ///       <see href="https://tools.ietf.org/html/rfc2109">RFC 2109</see>
+  ///       </term>
+  ///     </item>
+  ///     <item>
+  ///       <term>
+  ///       <see href="https://tools.ietf.org/html/rfc2965">RFC 2965</see>
+  ///       </term>
+  ///     </item>
+  ///     <item>
+  ///       <term>
+  ///       <see href="https://tools.ietf.org/html/rfc6265">RFC 6265</see>
+  ///       </term>
+  ///     </item>
+  ///   </list>
+  ///   <para>
+  ///   This class cannot be inherited.
+  ///   </para>
+  /// </remarks>
+  [Serializable]
+  public sealed class Cookie
+  {
+    #region Private Fields
+
+    private string                 _comment;
+    private Uri                    _commentUri;
+    private bool                   _discard;
+    private string                 _domain;
+    private static readonly int[]  _emptyPorts;
+    private DateTime               _expires;
+    private bool                   _httpOnly;
+    private string                 _name;
+    private string                 _path;
+    private string                 _port;
+    private int[]                  _ports;
+    private static readonly char[] _reservedCharsForValue;
+    private string                 _sameSite;
+    private bool                   _secure;
+    private DateTime               _timeStamp;
+    private string                 _value;
+    private int                    _version;
+
+    #endregion
+
+    #region Static Constructor
+
+    static Cookie ()
+    {
+      _emptyPorts = new int[0];
+      _reservedCharsForValue = new[] { ';', ',' };
+    }
+
+    #endregion
+
+    #region Internal Constructors
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Cookie"/> class.
+    /// </summary>
+    internal Cookie ()
+    {
+      init (String.Empty, String.Empty, String.Empty, String.Empty);
+    }
+
+    #endregion
+
+    #region Public Constructors
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Cookie"/> class with
+    /// the specified name and value.
+    /// </summary>
+    /// <param name="name">
+    ///   <para>
+    ///   A <see cref="string"/> that specifies the name of the cookie.
+    ///   </para>
+    ///   <para>
+    ///   The name must be a token defined in
+    ///   <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
+    ///   RFC 2616</see>.
+    ///   </para>
+    /// </param>
+    /// <param name="value">
+    /// A <see cref="string"/> that specifies the value of the cookie.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="name"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   <paramref name="name"/> is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> starts with a dollar sign.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="value"/> is a string not enclosed in double quotes
+    ///   that contains an invalid character.
+    ///   </para>
+    /// </exception>
+    public Cookie (string name, string value)
+      : this (name, value, String.Empty, String.Empty)
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Cookie"/> class with
+    /// the specified name, value, and path.
+    /// </summary>
+    /// <param name="name">
+    ///   <para>
+    ///   A <see cref="string"/> that specifies the name of the cookie.
+    ///   </para>
+    ///   <para>
+    ///   The name must be a token defined in
+    ///   <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
+    ///   RFC 2616</see>.
+    ///   </para>
+    /// </param>
+    /// <param name="value">
+    /// A <see cref="string"/> that specifies the value of the cookie.
+    /// </param>
+    /// <param name="path">
+    /// A <see cref="string"/> that specifies the value of the Path
+    /// attribute of the cookie.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="name"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   <paramref name="name"/> is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> starts with a dollar sign.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="value"/> is a string not enclosed in double quotes
+    ///   that contains an invalid character.
+    ///   </para>
+    /// </exception>
+    public Cookie (string name, string value, string path)
+      : this (name, value, path, String.Empty)
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Cookie"/> class with
+    /// the specified name, value, path, and domain.
+    /// </summary>
+    /// <param name="name">
+    ///   <para>
+    ///   A <see cref="string"/> that specifies the name of the cookie.
+    ///   </para>
+    ///   <para>
+    ///   The name must be a token defined in
+    ///   <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
+    ///   RFC 2616</see>.
+    ///   </para>
+    /// </param>
+    /// <param name="value">
+    /// A <see cref="string"/> that specifies the value of the cookie.
+    /// </param>
+    /// <param name="path">
+    /// A <see cref="string"/> that specifies the value of the Path
+    /// attribute of the cookie.
+    /// </param>
+    /// <param name="domain">
+    /// A <see cref="string"/> that specifies the value of the Domain
+    /// attribute of the cookie.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="name"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   <paramref name="name"/> is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> starts with a dollar sign.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="value"/> is a string not enclosed in double quotes
+    ///   that contains an invalid character.
+    ///   </para>
+    /// </exception>
+    public Cookie (string name, string value, string path, string domain)
+    {
+      if (name == null)
+        throw new ArgumentNullException ("name");
+
+      if (name.Length == 0)
+        throw new ArgumentException ("An empty string.", "name");
+
+      if (name[0] == '$') {
+        var msg = "It starts with a dollar sign.";
+        throw new ArgumentException (msg, "name");
+      }
+
+      if (!name.IsToken ()) {
+        var msg = "It contains an invalid character.";
+        throw new ArgumentException (msg, "name");
+      }
+
+      if (value == null)
+        value = String.Empty;
+
+      if (value.Contains (_reservedCharsForValue)) {
+        if (!value.IsEnclosedIn ('"')) {
+          var msg = "A string not enclosed in double quotes.";
+          throw new ArgumentException (msg, "value");
+        }
+      }
+
+      init (name, value, path ?? String.Empty, domain ?? String.Empty);
+    }
+
+    #endregion
+
+    #region Internal Properties
+
+    internal bool ExactDomain {
+      get {
+        return _domain.Length == 0 || _domain[0] != '.';
+      }
+    }
+
+    internal int MaxAge {
+      get {
+        if (_expires == DateTime.MinValue)
+          return 0;
+
+        var expires = _expires.Kind != DateTimeKind.Local
+                      ? _expires.ToLocalTime ()
+                      : _expires;
+
+        var span = expires - DateTime.Now;
+        return span > TimeSpan.Zero
+               ? (int) span.TotalSeconds
+               : 0;
+      }
+
+      set {
+        _expires = value > 0
+                   ? DateTime.Now.AddSeconds ((double) value)
+                   : DateTime.Now;
+      }
+    }
+
+    internal int[] Ports {
+      get {
+        return _ports ?? _emptyPorts;
+      }
+    }
+
+    internal string SameSite {
+      get {
+        return _sameSite;
+      }
+
+      set {
+        _sameSite = value;
+      }
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    /// <summary>
+    /// Gets the value of the Comment attribute of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the comment to document
+    ///   intended use of the cookie.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if not present.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see langword="null"/>.
+    ///   </para>
+    /// </value>
+    public string Comment {
+      get {
+        return _comment;
+      }
+
+      internal set {
+        _comment = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets the value of the CommentURL attribute of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="Uri"/> that represents the URI that provides
+    ///   the comment to document intended use of the cookie.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if not present.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see langword="null"/>.
+    ///   </para>
+    /// </value>
+    public Uri CommentUri {
+      get {
+        return _commentUri;
+      }
+
+      internal set {
+        _commentUri = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets a value indicating whether the client discards the cookie
+    /// unconditionally when the client terminates.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   <c>true</c> if the client discards the cookie unconditionally
+    ///   when the client terminates; otherwise, <c>false</c>.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <c>false</c>.
+    ///   </para>
+    /// </value>
+    public bool Discard {
+      get {
+        return _discard;
+      }
+
+      internal set {
+        _discard = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the value of the Domain attribute of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the domain name that
+    ///   the cookie is valid for.
+    ///   </para>
+    ///   <para>
+    ///   An empty string if this attribute is not needed.
+    ///   </para>
+    /// </value>
+    public string Domain {
+      get {
+        return _domain;
+      }
+
+      set {
+        _domain = value ?? String.Empty;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the cookie has expired.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   <c>true</c> if the cookie has expired; otherwise, <c>false</c>.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <c>false</c>.
+    ///   </para>
+    /// </value>
+    public bool Expired {
+      get {
+        return _expires != DateTime.MinValue && _expires <= DateTime.Now;
+      }
+
+      set {
+        _expires = value ? DateTime.Now : DateTime.MinValue;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the value of the Expires attribute of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="DateTime"/> that represents the date and time that
+    ///   the cookie expires on.
+    ///   </para>
+    ///   <para>
+    ///   <see cref="DateTime.MinValue"/> if this attribute is not needed.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see cref="DateTime.MinValue"/>.
+    ///   </para>
+    /// </value>
+    public DateTime Expires {
+      get {
+        return _expires;
+      }
+
+      set {
+        _expires = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether non-HTTP APIs can access
+    /// the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   <c>true</c> if non-HTTP APIs cannot access the cookie; otherwise,
+    ///   <c>false</c>.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <c>false</c>.
+    ///   </para>
+    /// </value>
+    public bool HttpOnly {
+      get {
+        return _httpOnly;
+      }
+
+      set {
+        _httpOnly = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the name of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the name of the cookie.
+    ///   </para>
+    ///   <para>
+    ///   The name must be a token defined in
+    ///   <see href="http://tools.ietf.org/html/rfc2616#section-2.2">
+    ///   RFC 2616</see>.
+    ///   </para>
+    /// </value>
+    /// <exception cref="ArgumentNullException">
+    /// The value specified for a set operation is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   The value specified for a set operation is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   The value specified for a set operation starts with a dollar sign.
+    ///   </para>
+    ///   <para>
+    ///   - or -
+    ///   </para>
+    ///   <para>
+    ///   The value specified for a set operation contains an invalid character.
+    ///   </para>
+    /// </exception>
+    public string Name {
+      get {
+        return _name;
+      }
+
+      set {
+        if (value == null)
+          throw new ArgumentNullException ("value");
+
+        if (value.Length == 0)
+          throw new ArgumentException ("An empty string.", "value");
+
+        if (value[0] == '$') {
+          var msg = "It starts with a dollar sign.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        if (!value.IsToken ()) {
+          var msg = "It contains an invalid character.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        _name = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the value of the Path attribute of the cookie.
+    /// </summary>
+    /// <value>
+    /// A <see cref="string"/> that represents the subset of URI on
+    /// the origin server that the cookie applies to.
+    /// </value>
+    public string Path {
+      get {
+        return _path;
+      }
+
+      set {
+        _path = value ?? String.Empty;
+      }
+    }
+
+    /// <summary>
+    /// Gets the value of the Port attribute of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the list of TCP ports
+    ///   that the cookie applies to.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if not present.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see langword="null"/>.
+    ///   </para>
+    /// </value>
+    public string Port {
+      get {
+        return _port;
+      }
+
+      internal set {
+        int[] ports;
+        if (!tryCreatePorts (value, out ports))
+          return;
+
+        _port = value;
+        _ports = ports;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the security level of
+    /// the cookie is secure.
+    /// </summary>
+    /// <remarks>
+    /// When this property is <c>true</c>, the cookie may be included in
+    /// the request only if the request is transmitted over HTTPS.
+    /// </remarks>
+    /// <value>
+    ///   <para>
+    ///   <c>true</c> if the security level of the cookie is secure;
+    ///   otherwise, <c>false</c>.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <c>false</c>.
+    ///   </para>
+    /// </value>
+    public bool Secure {
+      get {
+        return _secure;
+      }
+
+      set {
+        _secure = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets the time when the cookie was issued.
+    /// </summary>
+    /// <value>
+    /// A <see cref="DateTime"/> that represents the time when
+    /// the cookie was issued.
+    /// </value>
+    public DateTime TimeStamp {
+      get {
+        return _timeStamp;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the value of the cookie.
+    /// </summary>
+    /// <value>
+    /// A <see cref="string"/> that represents the value of the cookie.
+    /// </value>
+    /// <exception cref="ArgumentException">
+    /// The value specified for a set operation is a string not enclosed in
+    /// double quotes that contains an invalid character.
+    /// </exception>
+    public string Value {
+      get {
+        return _value;
+      }
+
+      set {
+        if (value == null)
+          value = String.Empty;
+
+        if (value.Contains (_reservedCharsForValue)) {
+          if (!value.IsEnclosedIn ('"')) {
+            var msg = "A string not enclosed in double quotes.";
+            throw new ArgumentException (msg, "value");
+          }
+        }
+
+        _value = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets the value of the Version attribute of the cookie.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   An <see cref="int"/> that represents the version of HTTP state
+    ///   management that the cookie conforms to.
+    ///   </para>
+    ///   <para>
+    ///   0 or 1. 0 if not present.
+    ///   </para>
+    ///   <para>
+    ///   The default value is 0.
+    ///   </para>
+    /// </value>
+    public int Version {
+      get {
+        return _version;
+      }
+
+      internal set {
+        if (value < 0 || value > 1)
+          return;
+
+        _version = value;
+      }
+    }
+
+    #endregion
+
+    #region Private Methods
+
+    private static int hash (int i, int j, int k, int l, int m)
+    {
+      return i
+             ^ (j << 13 | j >> 19)
+             ^ (k << 26 | k >>  6)
+             ^ (l <<  7 | l >> 25)
+             ^ (m << 20 | m >> 12);
+    }
+
+    private void init (string name, string value, string path, string domain)
+    {
+      _name = name;
+      _value = value;
+      _path = path;
+      _domain = domain;
+
+      _expires = DateTime.MinValue;
+      _timeStamp = DateTime.Now;
+    }
+
+    private string toResponseStringVersion0 ()
+    {
+      var buff = new StringBuilder (64);
+
+      buff.AppendFormat ("{0}={1}", _name, _value);
+
+      if (_expires != DateTime.MinValue) {
+        buff.AppendFormat (
+          "; Expires={0}",
+          _expires.ToUniversalTime ().ToString (
+            "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
+            CultureInfo.CreateSpecificCulture ("en-US")
+          )
+        );
+      }
+
+      if (!_path.IsNullOrEmpty ())
+        buff.AppendFormat ("; Path={0}", _path);
+
+      if (!_domain.IsNullOrEmpty ())
+        buff.AppendFormat ("; Domain={0}", _domain);
+
+      if (!_sameSite.IsNullOrEmpty ())
+        buff.AppendFormat ("; SameSite={0}", _sameSite);
+
+      if (_secure)
+        buff.Append ("; Secure");
+
+      if (_httpOnly)
+        buff.Append ("; HttpOnly");
+
+      return buff.ToString ();
+    }
+
+    private string toResponseStringVersion1 ()
+    {
+      var buff = new StringBuilder (64);
+
+      buff.AppendFormat ("{0}={1}; Version={2}", _name, _value, _version);
+
+      if (_expires != DateTime.MinValue)
+        buff.AppendFormat ("; Max-Age={0}", MaxAge);
+
+      if (!_path.IsNullOrEmpty ())
+        buff.AppendFormat ("; Path={0}", _path);
+
+      if (!_domain.IsNullOrEmpty ())
+        buff.AppendFormat ("; Domain={0}", _domain);
+
+      if (_port != null) {
+        if (_port != "\"\"")
+          buff.AppendFormat ("; Port={0}", _port);
+        else
+          buff.Append ("; Port");
+      }
+
+      if (_comment != null)
+        buff.AppendFormat ("; Comment={0}", HttpUtility.UrlEncode (_comment));
+
+      if (_commentUri != null) {
+        var url = _commentUri.OriginalString;
+        buff.AppendFormat (
+          "; CommentURL={0}", !url.IsToken () ? url.Quote () : url
+        );
+      }
+
+      if (_discard)
+        buff.Append ("; Discard");
+
+      if (_secure)
+        buff.Append ("; Secure");
+
+      return buff.ToString ();
+    }
+
+    private static bool tryCreatePorts (string value, out int[] result)
+    {
+      result = null;
+
+      var arr = value.Trim ('"').Split (',');
+      var len = arr.Length;
+      var res = new int[len];
+
+      for (var i = 0; i < len; i++) {
+        var s = arr[i].Trim ();
+        if (s.Length == 0) {
+          res[i] = Int32.MinValue;
+          continue;
+        }
+
+        if (!Int32.TryParse (s, out res[i]))
+          return false;
+      }
+
+      result = res;
+      return true;
+    }
+
+    #endregion
+
+    #region Internal Methods
+
+    internal bool EqualsWithoutValue (Cookie cookie)
+    {
+      var caseSensitive = StringComparison.InvariantCulture;
+      var caseInsensitive = StringComparison.InvariantCultureIgnoreCase;
+
+      return _name.Equals (cookie._name, caseInsensitive)
+             && _path.Equals (cookie._path, caseSensitive)
+             && _domain.Equals (cookie._domain, caseInsensitive)
+             && _version == cookie._version;
+    }
+
+    internal bool EqualsWithoutValueAndVersion (Cookie cookie)
+    {
+      var caseSensitive = StringComparison.InvariantCulture;
+      var caseInsensitive = StringComparison.InvariantCultureIgnoreCase;
+
+      return _name.Equals (cookie._name, caseInsensitive)
+             && _path.Equals (cookie._path, caseSensitive)
+             && _domain.Equals (cookie._domain, caseInsensitive);
+    }
+
+    internal string ToRequestString (Uri uri)
+    {
+      if (_name.Length == 0)
+        return String.Empty;
+
+      if (_version == 0)
+        return String.Format ("{0}={1}", _name, _value);
+
+      var buff = new StringBuilder (64);
+
+      buff.AppendFormat ("$Version={0}; {1}={2}", _version, _name, _value);
+
+      if (!_path.IsNullOrEmpty ())
+        buff.AppendFormat ("; $Path={0}", _path);
+      else if (uri != null)
+        buff.AppendFormat ("; $Path={0}", uri.GetAbsolutePath ());
+      else
+        buff.Append ("; $Path=/");
+
+      if (!_domain.IsNullOrEmpty ()) {
+        if (uri == null || uri.Host != _domain)
+          buff.AppendFormat ("; $Domain={0}", _domain);
+      }
+
+      if (_port != null) {
+        if (_port != "\"\"")
+          buff.AppendFormat ("; $Port={0}", _port);
+        else
+          buff.Append ("; $Port");
+      }
+
+      return buff.ToString ();
+    }
+
+    /// <summary>
+    /// Returns a string that represents the current cookie instance.
+    /// </summary>
+    /// <returns>
+    /// A <see cref="string"/> that is suitable for the Set-Cookie response
+    /// header.
+    /// </returns>
+    internal string ToResponseString ()
+    {
+      return _name.Length == 0
+             ? String.Empty
+             : _version == 0
+               ? toResponseStringVersion0 ()
+               : toResponseStringVersion1 ();
+    }
+
+    internal static bool TryCreate (
+      string name, string value, out Cookie result
+    )
+    {
+      result = null;
+
+      try {
+        result = new Cookie (name, value);
+      }
+      catch {
+        return false;
+      }
+
+      return true;
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    /// <summary>
+    /// Determines whether the current cookie instance is equal to
+    /// the specified <see cref="object"/> instance.
+    /// </summary>
+    /// <param name="comparand">
+    ///   <para>
+    ///   An <see cref="object"/> instance to compare with
+    ///   the current cookie instance.
+    ///   </para>
+    ///   <para>
+    ///   An reference to a <see cref="Cookie"/> instance.
+    ///   </para>
+    /// </param>
+    /// <returns>
+    /// <c>true</c> if the current cookie instance is equal to
+    /// <paramref name="comparand"/>; otherwise, <c>false</c>.
+    /// </returns>
+    public override bool Equals (object comparand)
+    {
+      var cookie = comparand as Cookie;
+      if (cookie == null)
+        return false;
+
+      var caseSensitive = StringComparison.InvariantCulture;
+      var caseInsensitive = StringComparison.InvariantCultureIgnoreCase;
+
+      return _name.Equals (cookie._name, caseInsensitive)
+             && _value.Equals (cookie._value, caseSensitive)
+             && _path.Equals (cookie._path, caseSensitive)
+             && _domain.Equals (cookie._domain, caseInsensitive)
+             && _version == cookie._version;
+    }
+
+    /// <summary>
+    /// Gets a hash code for the current cookie instance.
+    /// </summary>
+    /// <returns>
+    /// An <see cref="int"/> that represents the hash code.
+    /// </returns>
+    public override int GetHashCode ()
+    {
+      return hash (
+               StringComparer.InvariantCultureIgnoreCase.GetHashCode (_name),
+               _value.GetHashCode (),
+               _path.GetHashCode (),
+               StringComparer.InvariantCultureIgnoreCase.GetHashCode (_domain),
+               _version
+             );
+    }
+
+    /// <summary>
+    /// Returns a string that represents the current cookie instance.
+    /// </summary>
+    /// <returns>
+    /// A <see cref="string"/> that is suitable for the Cookie request header.
+    /// </returns>
+    public override string ToString ()
+    {
+      return ToRequestString (null);
+    }
+
+    #endregion
+  }
+}

+ 821 - 0
src/websocket-sharp/Net/CookieCollection.cs

@@ -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 <[email protected]>
+ * - Gonzalo Paniagua Javier <[email protected]>
+ * - Sebastien Pouliot <[email protected]>
+ */
+#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 - 0
src/websocket-sharp/Net/CookieException.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 582 - 0
src/websocket-sharp/Net/EndPointListener.cs

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

+ 261 - 0
src/websocket-sharp/Net/EndPointManager.cs

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

+ 82 - 0
src/websocket-sharp/Net/HttpBasicIdentity.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 617 - 0
src/websocket-sharp/Net/HttpConnection.cs

@@ -0,0 +1,617 @@
+#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-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 <[email protected]>
+ */
+#endregion
+
+#region Contributors
+/*
+ * Contributors:
+ * - Liryna <[email protected]>
+ * - Rohan Singh <[email protected]>
+ */
+#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 static readonly int   _bufferLength;
+    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 static readonly int   _maxInputLength;
+    private ResponseStream        _outputStream;
+    private int                   _position;
+    private EndPoint              _remoteEndPoint;
+    private MemoryStream          _requestBuffer;
+    private int                   _reuses;
+    private bool                  _secure;
+    private Socket                _socket;
+    private Stream                _stream;
+    private object                _sync;
+    private int                   _timeout;
+    private Dictionary<int, bool> _timeoutCanceled;
+    private Timer                 _timer;
+
+    #endregion
+
+    #region Static Constructor
+
+    static HttpConnection ()
+    {
+      _bufferLength = 8192;
+      _maxInputLength = 32768;
+    }
+
+    #endregion
+
+    #region Internal Constructors
+
+    internal HttpConnection (Socket socket, EndPointListener listener)
+    {
+      _socket = socket;
+      _listener = listener;
+
+      var netStream = new NetworkStream (socket, false);
+
+      if (listener.IsSecure) {
+        var sslConf = listener.SslConfiguration;
+        var sslStream = new SslStream (
+                          netStream,
+                          false,
+                          sslConf.ClientCertificateValidationCallback
+                        );
+
+        sslStream.AuthenticateAsServer (
+          sslConf.ServerCertificate,
+          sslConf.ClientCertificateRequired,
+          sslConf.EnabledSslProtocols,
+          sslConf.CheckCertificateRevocation
+        );
+
+        _secure = true;
+        _stream = sslStream;
+      }
+      else {
+        _stream = netStream;
+      }
+
+      _buffer = new byte[_bufferLength];
+      _localEndPoint = socket.LocalEndPoint;
+      _remoteEndPoint = socket.RemoteEndPoint;
+      _sync = new object ();
+      _timeoutCanceled = new Dictionary<int, bool> ();
+      _timer = new Timer (onTimeout, this, Timeout.Infinite, Timeout.Infinite);
+
+      init (90000); // 90k ms for first request, 15k ms from then on.
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    public bool IsClosed {
+      get {
+        return _socket == null;
+      }
+    }
+
+    public bool IsLocal {
+      get {
+        return ((IPEndPoint) _remoteEndPoint).Address.IsLocal ();
+      }
+    }
+
+    public bool IsSecure {
+      get {
+        return _secure;
+      }
+    }
+
+    public IPEndPoint LocalEndPoint {
+      get {
+        return (IPEndPoint) _localEndPoint;
+      }
+    }
+
+    public IPEndPoint RemoteEndPoint {
+      get {
+        return (IPEndPoint) _remoteEndPoint;
+      }
+    }
+
+    public int Reuses {
+      get {
+        return _reuses;
+      }
+    }
+
+    public Stream Stream {
+      get {
+        return _stream;
+      }
+    }
+
+    #endregion
+
+    #region Private Methods
+
+    private void close ()
+    {
+      lock (_sync) {
+        if (_socket == null)
+          return;
+
+        disposeTimer ();
+        disposeRequestBuffer ();
+        disposeStream ();
+        closeSocket ();
+      }
+
+      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;
+
+      _stream.Dispose ();
+
+      _stream = null;
+    }
+
+    private void disposeTimer ()
+    {
+      if (_timer == null)
+        return;
+
+      try {
+        _timer.Change (Timeout.Infinite, Timeout.Infinite);
+      }
+      catch {
+      }
+
+      _timer.Dispose ();
+
+      _timer = null;
+    }
+
+    private void init (int timeout)
+    {
+      _timeout = timeout;
+
+      _context = new HttpListenerContext (this);
+      _currentLine = new StringBuilder (64);
+      _inputState = InputState.RequestLine;
+      _inputStream = null;
+      _lineState = LineState.None;
+      _outputStream = null;
+      _position = 0;
+      _requestBuffer = new MemoryStream ();
+    }
+
+    private static void onRead (IAsyncResult asyncResult)
+    {
+      var conn = (HttpConnection) asyncResult.AsyncState;
+      var current = conn._reuses;
+
+      if (conn._socket == null)
+        return;
+
+      lock (conn._sync) {
+        if (conn._socket == null)
+          return;
+
+        if (!conn._timeoutCanceled[current]) {
+          conn._timer.Change (Timeout.Infinite, Timeout.Infinite);
+          conn._timeoutCanceled[current] = true;
+        }
+
+        var nread = 0;
+
+        try {
+          nread = conn._stream.EndRead (asyncResult);
+        }
+        catch (Exception) {
+          // TODO: Logging.
+
+          conn.close ();
+
+          return;
+        }
+
+        if (nread <= 0) {
+          conn.close ();
+
+          return;
+        }
+
+        conn._requestBuffer.Write (conn._buffer, 0, nread);
+        var len = (int) conn._requestBuffer.Length;
+
+        if (conn.processInput (conn._requestBuffer.GetBuffer (), len)) {
+          if (!conn._context.HasErrorMessage)
+            conn._context.Request.FinishInitialization ();
+
+          if (conn._context.HasErrorMessage) {
+            conn._context.SendError ();
+
+            return;
+          }
+
+          var url = conn._context.Request.Url;
+          HttpListener lsnr;
+
+          if (conn._listener.TrySearchHttpListener (url, out lsnr)) {
+            conn.registerContext (lsnr);
+
+            return;
+          }
+
+          conn._context.ErrorStatusCode = 404;
+          conn._context.SendError ();
+
+          return;
+        }
+
+        try {
+          conn._stream.BeginRead (conn._buffer, 0, _bufferLength, onRead, conn);
+        }
+        catch (Exception) {
+          // TODO: Logging.
+
+          conn.close ();
+        }
+      }
+    }
+
+    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._context.ErrorStatusCode = 408;
+        conn._context.SendError ();
+      }
+    }
+
+    private bool processInput (byte[] data, int length)
+    {
+      // This method returns a bool:
+      // - true  Done processing
+      // - false Need more input
+
+      try {
+        while (true) {
+          int nread;
+          var line = readLineFrom (data, _position, length, out nread);
+
+          _position += nread;
+
+          if (line == null)
+            break;
+
+          if (line.Length == 0) {
+            if (_inputState == InputState.RequestLine)
+              continue;
+
+            if (_position > _maxInputLength)
+              _context.ErrorMessage = "Headers too long";
+
+            return true;
+          }
+
+          if (_inputState == InputState.RequestLine) {
+            _context.Request.SetRequestLine (line);
+            _inputState = InputState.Headers;
+          }
+          else {
+            _context.Request.AddHeader (line);
+          }
+
+          if (_context.HasErrorMessage)
+            return true;
+        }
+      }
+      catch (Exception ex) {
+        _context.ErrorMessage = ex.Message;
+
+        return true;
+      }
+
+      if (_position >= _maxInputLength) {
+        _context.ErrorMessage = "Headers too long";
+
+        return true;
+      }
+
+      return false;
+    }
+
+    private string readLineFrom (
+      byte[] buffer, int offset, int length, out int nread
+    )
+    {
+      nread = 0;
+
+      for (var i = offset; i < length; i++) {
+        nread++;
+
+        var b = buffer[i];
+
+        if (b == 13) {
+          _lineState = LineState.Cr;
+
+          continue;
+        }
+
+        if (b == 10) {
+          _lineState = LineState.Lf;
+
+          break;
+        }
+
+        _currentLine.Append ((char) b);
+      }
+
+      if (_lineState != LineState.Lf)
+        return null;
+
+      var ret = _currentLine.ToString ();
+
+      _currentLine.Length = 0;
+      _lineState = LineState.None;
+
+      return ret;
+    }
+
+    private void registerContext (HttpListener listener)
+    {
+      if (_lastListener != listener) {
+        removeConnection ();
+
+        if (!listener.AddConnection (this)) {
+          close ();
+
+          return;
+        }
+
+        _lastListener = listener;
+      }
+
+      _context.Listener = listener;
+
+      if (!_context.Authenticate ())
+        return;
+
+      if (!_context.Register ())
+        return;
+
+      _contextRegistered = true;
+    }
+
+    private void removeConnection ()
+    {
+      if (_lastListener == null) {
+        _listener.RemoveConnection (this);
+
+        return;
+      }
+
+      _lastListener.RemoveConnection (this);
+    }
+
+    private void unregisterContext ()
+    {
+      if (!_contextRegistered)
+        return;
+
+      _context.Unregister ();
+
+      _contextRegistered = false;
+    }
+
+    #endregion
+
+    #region Internal Methods
+
+    internal void BeginReadRequest ()
+    {
+      _timeoutCanceled.Add (_reuses, false);
+      _timer.Change (_timeout, Timeout.Infinite);
+
+      try {
+        _stream.BeginRead (_buffer, 0, _bufferLength, onRead, this);
+      }
+      catch (Exception) {
+        // TODO: Logging.
+
+        close ();
+      }
+    }
+
+    internal void Close (bool force)
+    {
+      if (_socket == null)
+        return;
+
+      lock (_sync) {
+        if (_socket == null)
+          return;
+
+        if (force) {
+          if (_outputStream != null)
+            _outputStream.Close (true);
+
+          close ();
+
+          return;
+        }
+
+        GetResponseStream ().Close (false);
+
+        if (_context.Response.CloseConnection) {
+          close ();
+
+          return;
+        }
+
+        if (!_context.Request.FlushInput ()) {
+          close ();
+
+          return;
+        }
+
+        disposeRequestBuffer ();
+        unregisterContext ();
+
+        _reuses++;
+
+        init (15000);
+        BeginReadRequest ();
+      }
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    public void Close ()
+    {
+      Close (false);
+    }
+
+    public RequestStream GetRequestStream (long contentLength, bool chunked)
+    {
+      lock (_sync) {
+        if (_socket == null)
+          return null;
+
+        if (_inputStream != null)
+          return _inputStream;
+
+        var buff = _requestBuffer.GetBuffer ();
+        var len = (int) _requestBuffer.Length;
+        var cnt = len - _position;
+
+        disposeRequestBuffer ();
+
+        _inputStream = chunked
+                       ? new ChunkedRequestStream (
+                           _stream, buff, _position, cnt, _context
+                         )
+                       : new RequestStream (
+                           _stream, buff, _position, cnt, contentLength
+                         );
+
+        return _inputStream;
+      }
+    }
+
+    public ResponseStream GetResponseStream ()
+    {
+      lock (_sync) {
+        if (_socket == null)
+          return null;
+
+        if (_outputStream != null)
+          return _outputStream;
+
+        var lsnr = _context.Listener;
+        var ignore = lsnr != null ? lsnr.IgnoreWriteExceptions : true;
+        _outputStream = new ResponseStream (_stream, _context.Response, ignore);
+
+        return _outputStream;
+      }
+    }
+
+    #endregion
+  }
+}

+ 187 - 0
src/websocket-sharp/Net/HttpDigestIdentity.cs

@@ -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 - 0
src/websocket-sharp/Net/HttpHeaderInfo.cs

@@ -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 - 0
src/websocket-sharp/Net/HttpHeaderType.cs

@@ -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 - 0
src/websocket-sharp/Net/HttpListener.cs

@@ -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 <[email protected]>
+ */
+#endregion
+
+#region Contributors
+/*
+ * Contributors:
+ * - Liryna <[email protected]>
+ */
+#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&lt;<see cref="HttpListenerRequest"/>, <see cref="AuthenticationSchemes"/>&gt;</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&lt;<see cref="IIdentity"/>, <see cref="NetworkCredential"/>&gt;</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 - 0
src/websocket-sharp/Net/HttpListenerAsyncResult.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 340 - 0
src/websocket-sharp/Net/HttpListenerContext.cs

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

+ 127 - 0
src/websocket-sharp/Net/HttpListenerException.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 273 - 0
src/websocket-sharp/Net/HttpListenerPrefix.cs

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

+ 299 - 0
src/websocket-sharp/Net/HttpListenerPrefixCollection.cs

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

+ 959 - 0
src/websocket-sharp/Net/HttpListenerRequest.cs

@@ -0,0 +1,959 @@
+#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 <[email protected]>
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+
+namespace WebSocketSharp.Net
+{
+  /// <summary>
+  /// Represents an incoming HTTP request to a <see cref="HttpListener"/>
+  /// instance.
+  /// </summary>
+  /// <remarks>
+  /// This class cannot be inherited.
+  /// </remarks>
+  public sealed class HttpListenerRequest
+  {
+    #region Private Fields
+
+    private static readonly byte[] _100continue;
+    private string[]               _acceptTypes;
+    private bool                   _chunked;
+    private HttpConnection         _connection;
+    private Encoding               _contentEncoding;
+    private long                   _contentLength;
+    private HttpListenerContext    _context;
+    private CookieCollection       _cookies;
+    private WebHeaderCollection    _headers;
+    private string                 _httpMethod;
+    private Stream                 _inputStream;
+    private Version                _protocolVersion;
+    private NameValueCollection    _queryString;
+    private string                 _rawUrl;
+    private Guid                   _requestTraceIdentifier;
+    private Uri                    _url;
+    private Uri                    _urlReferrer;
+    private bool                   _urlSet;
+    private string                 _userHostName;
+    private string[]               _userLanguages;
+
+    #endregion
+
+    #region Static Constructor
+
+    static HttpListenerRequest ()
+    {
+      _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
+    }
+
+    #endregion
+
+    #region Internal Constructors
+
+    internal HttpListenerRequest (HttpListenerContext context)
+    {
+      _context = context;
+
+      _connection = context.Connection;
+      _contentLength = -1;
+      _headers = new WebHeaderCollection ();
+      _requestTraceIdentifier = Guid.NewGuid ();
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    /// <summary>
+    /// Gets the media types that are acceptable for the client.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   An array of <see cref="string"/> that contains the names of the media
+    ///   types specified in the value of the Accept header.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if the header is not present.
+    ///   </para>
+    /// </value>
+    public string[] AcceptTypes {
+      get {
+        var val = _headers["Accept"];
+
+        if (val == null)
+          return null;
+
+        if (_acceptTypes == null) {
+          _acceptTypes = val
+                         .SplitHeaderValue (',')
+                         .TrimEach ()
+                         .ToList ()
+                         .ToArray ();
+        }
+
+        return _acceptTypes;
+      }
+    }
+
+    /// <summary>
+    /// Gets an error code that identifies a problem with the certificate
+    /// provided by the client.
+    /// </summary>
+    /// <value>
+    /// An <see cref="int"/> that represents an error code.
+    /// </value>
+    /// <exception cref="NotSupportedException">
+    /// This property is not supported.
+    /// </exception>
+    public int ClientCertificateError {
+      get {
+        throw new NotSupportedException ();
+      }
+    }
+
+    /// <summary>
+    /// Gets the encoding for the entity body data included in the request.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="Encoding"/> converted from the charset value of the
+    ///   Content-Type header.
+    ///   </para>
+    ///   <para>
+    ///   <see cref="Encoding.UTF8"/> if the charset value is not available.
+    ///   </para>
+    /// </value>
+    public Encoding ContentEncoding {
+      get {
+        if (_contentEncoding == null)
+          _contentEncoding = getContentEncoding ();
+
+        return _contentEncoding;
+      }
+    }
+
+    /// <summary>
+    /// Gets the length in bytes of the entity body data included in the
+    /// request.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="long"/> converted from the value of the Content-Length
+    ///   header.
+    ///   </para>
+    ///   <para>
+    ///   -1 if the header is not present.
+    ///   </para>
+    /// </value>
+    public long ContentLength64 {
+      get {
+        return _contentLength;
+      }
+    }
+
+    /// <summary>
+    /// Gets the media type of the entity body data included in the request.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the value of the Content-Type
+    ///   header.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if the header is not present.
+    ///   </para>
+    /// </value>
+    public string ContentType {
+      get {
+        return _headers["Content-Type"];
+      }
+    }
+
+    /// <summary>
+    /// Gets the cookies included in the request.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="CookieCollection"/> that contains the cookies.
+    ///   </para>
+    ///   <para>
+    ///   An empty collection if not included.
+    ///   </para>
+    /// </value>
+    public CookieCollection Cookies {
+      get {
+        if (_cookies == null)
+          _cookies = _headers.GetCookies (false);
+
+        return _cookies;
+      }
+    }
+
+    /// <summary>
+    /// Gets a value indicating whether the request has the entity body data.
+    /// </summary>
+    /// <value>
+    /// <c>true</c> if the request has the entity body data; otherwise,
+    /// <c>false</c>.
+    /// </value>
+    public bool HasEntityBody {
+      get {
+        return _contentLength > 0 || _chunked;
+      }
+    }
+
+    /// <summary>
+    /// Gets the headers included in the request.
+    /// </summary>
+    /// <value>
+    /// A <see cref="NameValueCollection"/> that contains the headers.
+    /// </value>
+    public NameValueCollection Headers {
+      get {
+        return _headers;
+      }
+    }
+
+    /// <summary>
+    /// Gets the HTTP method specified by the client.
+    /// </summary>
+    /// <value>
+    /// A <see cref="string"/> that represents the HTTP method specified in
+    /// the request line.
+    /// </value>
+    public string HttpMethod {
+      get {
+        return _httpMethod;
+      }
+    }
+
+    /// <summary>
+    /// Gets a stream that contains the entity body data included in
+    /// the request.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="Stream"/> that contains the entity body data.
+    ///   </para>
+    ///   <para>
+    ///   <see cref="Stream.Null"/> if the entity body data is not available.
+    ///   </para>
+    /// </value>
+    public Stream InputStream {
+      get {
+        if (_inputStream == null) {
+          _inputStream = _contentLength > 0 || _chunked
+                         ? _connection
+                           .GetRequestStream (_contentLength, _chunked)
+                         : Stream.Null;
+        }
+
+        return _inputStream;
+      }
+    }
+
+    /// <summary>
+    /// Gets a value indicating whether the client is authenticated.
+    /// </summary>
+    /// <value>
+    /// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
+    /// </value>
+    public bool IsAuthenticated {
+      get {
+        return _context.User != null;
+      }
+    }
+
+    /// <summary>
+    /// Gets a value indicating whether the request is sent from the local
+    /// computer.
+    /// </summary>
+    /// <value>
+    /// <c>true</c> if the request is sent from the same computer as the server;
+    /// otherwise, <c>false</c>.
+    /// </value>
+    public bool IsLocal {
+      get {
+        return _connection.IsLocal;
+      }
+    }
+
+    /// <summary>
+    /// Gets a value indicating whether a secure connection is used to send
+    /// the request.
+    /// </summary>
+    /// <value>
+    /// <c>true</c> if the connection is secure; otherwise, <c>false</c>.
+    /// </value>
+    public bool IsSecureConnection {
+      get {
+        return _connection.IsSecure;
+      }
+    }
+
+    /// <summary>
+    /// Gets a value indicating whether the request is a WebSocket handshake
+    /// request.
+    /// </summary>
+    /// <value>
+    /// <c>true</c> if the request is a WebSocket handshake request; otherwise,
+    /// <c>false</c>.
+    /// </value>
+    public bool IsWebSocketRequest {
+      get {
+        return _httpMethod == "GET"
+               && _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 (',').TrimEach ().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 Encoding.UTF8;
+
+      Encoding ret;
+
+      return HttpUtility.TryGetEncoding (val, out ret)
+             ? ret
+             : Encoding.UTF8;
+    }
+
+    #endregion
+
+    #region Internal Methods
+
+    internal void AddHeader (string headerField)
+    {
+      var start = headerField[0];
+
+      if (start == ' ' || start == '\t') {
+        _context.ErrorMessage = "Invalid header field";
+
+        return;
+      }
+
+      var colon = headerField.IndexOf (':');
+
+      if (colon < 1) {
+        _context.ErrorMessage = "Invalid header field";
+
+        return;
+      }
+
+      var name = headerField.Substring (0, colon).Trim ();
+
+      if (name.Length == 0 || !name.IsToken ()) {
+        _context.ErrorMessage = "Invalid header name";
+
+        return;
+      }
+
+      var val = colon < headerField.Length - 1
+                ? headerField.Substring (colon + 1).Trim ()
+                : String.Empty;
+
+      _headers.InternalSet (name, val, false);
+
+      var lower = name.ToLower (CultureInfo.InvariantCulture);
+
+      if (lower == "host") {
+        if (_userHostName != null) {
+          _context.ErrorMessage = "Invalid Host header";
+
+          return;
+        }
+
+        if (val.Length == 0) {
+          _context.ErrorMessage = "Invalid Host header";
+
+          return;
+        }
+
+        _userHostName = val;
+
+        return;
+      }
+
+      if (lower == "content-length") {
+        if (_contentLength > -1) {
+          _context.ErrorMessage = "Invalid Content-Length header";
+
+          return;
+        }
+
+        long len;
+
+        if (!Int64.TryParse (val, out len)) {
+          _context.ErrorMessage = "Invalid Content-Length header";
+
+          return;
+        }
+
+        if (len < 0) {
+          _context.ErrorMessage = "Invalid Content-Length header";
+
+          return;
+        }
+
+        _contentLength = len;
+
+        return;
+      }
+    }
+
+    internal void FinishInitialization ()
+    {
+      if (_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.ErrorStatusCode = 501;
+
+          return;
+        }
+
+        _chunked = true;
+      }
+
+      if (_httpMethod == "POST" || _httpMethod == "PUT") {
+        if (_contentLength <= 0 && !_chunked) {
+          _context.ErrorMessage = String.Empty;
+          _context.ErrorStatusCode = 411;
+
+          return;
+        }
+      }
+
+      var expect = _headers["Expect"];
+
+      if (expect != null) {
+        var comparison = StringComparison.OrdinalIgnoreCase;
+
+        if (!expect.Equals ("100-continue", comparison)) {
+          _context.ErrorMessage = "Invalid Expect header";
+
+          return;
+        }
+
+        var output = _connection.GetResponseStream ();
+        output.InternalWrite (_100continue, 0, _100continue.Length);
+      }
+    }
+
+    internal bool FlushInput ()
+    {
+      var input = InputStream;
+
+      if (input == Stream.Null)
+        return true;
+
+      var len = 2048;
+
+      if (_contentLength > 0 && _contentLength < len)
+        len = (int) _contentLength;
+
+      var buff = new byte[len];
+
+      while (true) {
+        try {
+          var ares = input.BeginRead (buff, 0, len, null, null);
+
+          if (!ares.IsCompleted) {
+            var timeout = 100;
+
+            if (!ares.AsyncWaitHandle.WaitOne (timeout))
+              return false;
+          }
+
+          if (input.EndRead (ares) <= 0)
+            return true;
+        }
+        catch {
+          return false;
+        }
+      }
+    }
+
+    internal bool IsUpgradeRequest (string protocol)
+    {
+      return _headers.Upgrades (protocol);
+    }
+
+    internal void SetRequestLine (string requestLine)
+    {
+      var parts = requestLine.Split (new[] { ' ' }, 3);
+
+      if (parts.Length < 3) {
+        _context.ErrorMessage = "Invalid request line (parts)";
+
+        return;
+      }
+
+      var method = parts[0];
+
+      if (method.Length == 0) {
+        _context.ErrorMessage = "Invalid request line (method)";
+
+        return;
+      }
+
+      var target = parts[1];
+
+      if (target.Length == 0) {
+        _context.ErrorMessage = "Invalid request line (target)";
+
+        return;
+      }
+
+      var rawVer = parts[2];
+
+      if (rawVer.Length != 8) {
+        _context.ErrorMessage = "Invalid request line (version)";
+
+        return;
+      }
+
+      if (rawVer.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 - 0
src/websocket-sharp/Net/HttpListenerResponse.cs

@@ -0,0 +1,1243 @@
+#region License
+/*
+ * HttpListenerResponse.cs
+ *
+ * This code is derived from HttpListenerResponse.cs (System.Net) of Mono
+ * (http://www.mono-project.com).
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+ * Copyright (c) 2012-2020 sta.blockhead
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#endregion
+
+#region Authors
+/*
+ * Authors:
+ * - Gonzalo Paniagua Javier <[email protected]>
+ */
+#endregion
+
+#region Contributors
+/*
+ * Contributors:
+ * - Nicholas Devenish
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace WebSocketSharp.Net
+{
+  /// <summary>
+  /// Represents an HTTP response to an HTTP request received by
+  /// a <see cref="HttpListener"/> instance.
+  /// </summary>
+  /// <remarks>
+  /// This class cannot be inherited.
+  /// </remarks>
+  public sealed class HttpListenerResponse : IDisposable
+  {
+    #region Private Fields
+
+    private bool                _closeConnection;
+    private Encoding            _contentEncoding;
+    private long                _contentLength;
+    private string              _contentType;
+    private HttpListenerContext _context;
+    private CookieCollection    _cookies;
+    private bool                _disposed;
+    private WebHeaderCollection _headers;
+    private bool                _headersSent;
+    private bool                _keepAlive;
+    private ResponseStream      _outputStream;
+    private Uri                 _redirectLocation;
+    private bool                _sendChunked;
+    private int                 _statusCode;
+    private string              _statusDescription;
+    private Version             _version;
+
+    #endregion
+
+    #region Internal Constructors
+
+    internal HttpListenerResponse (HttpListenerContext context)
+    {
+      _context = context;
+      _keepAlive = true;
+      _statusCode = 200;
+      _statusDescription = "OK";
+      _version = HttpVersion.Version11;
+    }
+
+    #endregion
+
+    #region Internal Properties
+
+    internal bool CloseConnection {
+      get {
+        return _closeConnection;
+      }
+
+      set {
+        _closeConnection = value;
+      }
+    }
+
+    internal WebHeaderCollection FullHeaders {
+      get {
+        var headers = new WebHeaderCollection (HttpHeaderType.Response, true);
+
+        if (_headers != null)
+          headers.Add (_headers);
+
+        if (_contentType != null) {
+          headers.InternalSet (
+            "Content-Type",
+            createContentTypeHeaderText (_contentType, _contentEncoding),
+            true
+          );
+        }
+
+        if (headers["Server"] == null)
+          headers.InternalSet ("Server", "websocket-sharp/1.0", true);
+
+        if (headers["Date"] == null) {
+          headers.InternalSet (
+            "Date",
+            DateTime.UtcNow.ToString ("r", CultureInfo.InvariantCulture),
+            true
+          );
+        }
+
+        if (_sendChunked) {
+          headers.InternalSet ("Transfer-Encoding", "chunked", true);
+        }
+        else {
+          headers.InternalSet (
+            "Content-Length",
+            _contentLength.ToString (CultureInfo.InvariantCulture),
+            true
+          );
+        }
+
+        /*
+         * Apache forces closing the connection for these status codes:
+         * - 400 Bad Request
+         * - 408 Request Timeout
+         * - 411 Length Required
+         * - 413 Request Entity Too Large
+         * - 414 Request-Uri Too Long
+         * - 500 Internal Server Error
+         * - 503 Service Unavailable
+         */
+        var closeConn = !_context.Request.KeepAlive
+                        || !_keepAlive
+                        || _statusCode == 400
+                        || _statusCode == 408
+                        || _statusCode == 411
+                        || _statusCode == 413
+                        || _statusCode == 414
+                        || _statusCode == 500
+                        || _statusCode == 503;
+
+        var reuses = _context.Connection.Reuses;
+
+        if (closeConn || reuses >= 100) {
+          headers.InternalSet ("Connection", "close", true);
+        }
+        else {
+          headers.InternalSet (
+            "Keep-Alive",
+            String.Format ("timeout=15,max={0}", 100 - reuses),
+            true
+          );
+
+          if (_context.Request.ProtocolVersion < HttpVersion.Version11)
+            headers.InternalSet ("Connection", "keep-alive", true);
+        }
+
+        if (_redirectLocation != null)
+          headers.InternalSet ("Location", _redirectLocation.AbsoluteUri, true);
+
+        if (_cookies != null) {
+          foreach (var cookie in _cookies) {
+            headers.InternalSet (
+              "Set-Cookie",
+              cookie.ToResponseString (),
+              true
+            );
+          }
+        }
+
+        return headers;
+      }
+    }
+
+    internal bool HeadersSent {
+      get {
+        return _headersSent;
+      }
+
+      set {
+        _headersSent = value;
+      }
+    }
+
+    internal string StatusLine {
+      get {
+        return String.Format (
+                 "HTTP/{0} {1} {2}\r\n",
+                 _version,
+                 _statusCode,
+                 _statusDescription
+               );
+      }
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    /// <summary>
+    /// Gets or sets the encoding for the entity body data included in
+    /// the response.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="Encoding"/> that represents the encoding for
+    ///   the entity body data.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if no encoding is specified.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see langword="null"/>.
+    ///   </para>
+    /// </value>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public Encoding ContentEncoding {
+      get {
+        return _contentEncoding;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        _contentEncoding = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the number of bytes in the entity body data included in
+    /// the response.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="long"/> that represents the number of bytes in
+    ///   the entity body data.
+    ///   </para>
+    ///   <para>
+    ///   It is used for the value of the Content-Length header.
+    ///   </para>
+    ///   <para>
+    ///   The default value is zero.
+    ///   </para>
+    /// </value>
+    /// <exception cref="ArgumentOutOfRangeException">
+    /// The value specified for a set operation is less than zero.
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public long ContentLength64 {
+      get {
+        return _contentLength;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        if (value < 0) {
+          var msg = "Less than zero.";
+          throw new ArgumentOutOfRangeException (msg, "value");
+        }
+
+        _contentLength = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the media type of the entity body included in
+    /// the response.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the media type of
+    ///   the entity body.
+    ///   </para>
+    ///   <para>
+    ///   It is used for the value of the Content-Type header.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if no media type is specified.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see langword="null"/>.
+    ///   </para>
+    /// </value>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   The value specified for a set operation is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   The value specified for a set operation contains
+    ///   an invalid character.
+    ///   </para>
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public string ContentType {
+      get {
+        return _contentType;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        if (value == null) {
+          _contentType = null;
+          return;
+        }
+
+        if (value.Length == 0) {
+          var msg = "An empty string.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        if (!isValidForContentType (value)) {
+          var msg = "It contains an invalid character.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        _contentType = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the collection of cookies sent with the response.
+    /// </summary>
+    /// <value>
+    /// A <see cref="CookieCollection"/> that contains the cookies sent with
+    /// the response.
+    /// </value>
+    public CookieCollection Cookies {
+      get {
+        if (_cookies == null)
+          _cookies = new CookieCollection ();
+
+        return _cookies;
+      }
+
+      set {
+        _cookies = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the collection of the HTTP headers sent to the client.
+    /// </summary>
+    /// <value>
+    /// A <see cref="WebHeaderCollection"/> that contains the headers sent to
+    /// the client.
+    /// </value>
+    /// <exception cref="InvalidOperationException">
+    /// The value specified for a set operation is not valid for a response.
+    /// </exception>
+    public WebHeaderCollection Headers {
+      get {
+        if (_headers == null)
+          _headers = new WebHeaderCollection (HttpHeaderType.Response, false);
+
+        return _headers;
+      }
+
+      set {
+        if (value == null) {
+          _headers = null;
+          return;
+        }
+
+        if (value.State != HttpHeaderType.Response) {
+          var msg = "The value is not valid for a response.";
+          throw new InvalidOperationException (msg);
+        }
+
+        _headers = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the server requests
+    /// a persistent connection.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   <c>true</c> if the server requests a persistent connection;
+    ///   otherwise, <c>false</c>.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <c>true</c>.
+    ///   </para>
+    /// </value>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public bool KeepAlive {
+      get {
+        return _keepAlive;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        _keepAlive = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets a stream instance to which the entity body data can be written.
+    /// </summary>
+    /// <value>
+    /// A <see cref="Stream"/> instance to which the entity body data can be
+    /// written.
+    /// </value>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public Stream OutputStream {
+      get {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_outputStream == null)
+          _outputStream = _context.Connection.GetResponseStream ();
+
+        return _outputStream;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the HTTP version used for the response.
+    /// </summary>
+    /// <value>
+    /// A <see cref="Version"/> that represents the HTTP version used for
+    /// the response.
+    /// </value>
+    /// <exception cref="ArgumentNullException">
+    /// The value specified for a set operation is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   The value specified for a set operation does not have its Major
+    ///   property set to 1.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   The value specified for a set operation does not have its Minor
+    ///   property set to either 0 or 1.
+    ///   </para>
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public Version ProtocolVersion {
+      get {
+        return _version;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        if (value == null)
+          throw new ArgumentNullException ("value");
+
+        if (value.Major != 1) {
+          var msg = "Its Major property is not 1.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        if (value.Minor < 0 || value.Minor > 1) {
+          var msg = "Its Minor property is not 0 or 1.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        _version = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the URL to which the client is redirected to locate
+    /// a requested resource.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the absolute URL for
+    ///   the redirect location.
+    ///   </para>
+    ///   <para>
+    ///   It is used for the value of the Location header.
+    ///   </para>
+    ///   <para>
+    ///   <see langword="null"/> if no redirect location is specified.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <see langword="null"/>.
+    ///   </para>
+    /// </value>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   The value specified for a set operation is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   The value specified for a set operation is not an absolute URL.
+    ///   </para>
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public string RedirectLocation {
+      get {
+        return _redirectLocation != null
+               ? _redirectLocation.OriginalString
+               : null;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        if (value == null) {
+          _redirectLocation = null;
+          return;
+        }
+
+        if (value.Length == 0) {
+          var msg = "An empty string.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        Uri uri;
+        if (!Uri.TryCreate (value, UriKind.Absolute, out uri)) {
+          var msg = "Not an absolute URL.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        _redirectLocation = uri;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the response uses the chunked
+    /// transfer encoding.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   <c>true</c> if the response uses the chunked transfer encoding;
+    ///   otherwise, <c>false</c>.
+    ///   </para>
+    ///   <para>
+    ///   The default value is <c>false</c>.
+    ///   </para>
+    /// </value>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public bool SendChunked {
+      get {
+        return _sendChunked;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        _sendChunked = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the HTTP status code returned to the client.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   An <see cref="int"/> that represents the HTTP status code for
+    ///   the response to the request.
+    ///   </para>
+    ///   <para>
+    ///   The default value is 200. It indicates that the request has
+    ///   succeeded.
+    ///   </para>
+    /// </value>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    /// <exception cref="System.Net.ProtocolViolationException">
+    ///   <para>
+    ///   The value specified for a set operation is invalid.
+    ///   </para>
+    ///   <para>
+    ///   Valid values are between 100 and 999 inclusive.
+    ///   </para>
+    /// </exception>
+    public int StatusCode {
+      get {
+        return _statusCode;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        if (value < 100 || value > 999) {
+          var msg = "A value is not between 100 and 999 inclusive.";
+          throw new System.Net.ProtocolViolationException (msg);
+        }
+
+        _statusCode = value;
+        _statusDescription = value.GetStatusDescription ();
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the description of the HTTP status code returned to
+    /// the client.
+    /// </summary>
+    /// <value>
+    ///   <para>
+    ///   A <see cref="string"/> that represents the description of
+    ///   the HTTP status code for the response to the request.
+    ///   </para>
+    ///   <para>
+    ///   The default value is
+    ///   the <see href="http://tools.ietf.org/html/rfc2616#section-10">
+    ///   RFC 2616</see> description for the <see cref="StatusCode"/>
+    ///   property value.
+    ///   </para>
+    ///   <para>
+    ///   An empty string if an RFC 2616 description does not exist.
+    ///   </para>
+    /// </value>
+    /// <exception cref="ArgumentNullException">
+    /// The value specified for a set operation is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    /// The value specified for a set operation contains an invalid character.
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public string StatusDescription {
+      get {
+        return _statusDescription;
+      }
+
+      set {
+        if (_disposed) {
+          var name = GetType ().ToString ();
+          throw new ObjectDisposedException (name);
+        }
+
+        if (_headersSent) {
+          var msg = "The response is already being sent.";
+          throw new InvalidOperationException (msg);
+        }
+
+        if (value == null)
+          throw new ArgumentNullException ("value");
+
+        if (value.Length == 0) {
+          _statusDescription = _statusCode.GetStatusDescription ();
+          return;
+        }
+
+        if (!isValidForStatusDescription (value)) {
+          var msg = "It contains an invalid character.";
+          throw new ArgumentException (msg, "value");
+        }
+
+        _statusDescription = value;
+      }
+    }
+
+    #endregion
+
+    #region Private Methods
+
+    private bool canSetCookie (Cookie cookie)
+    {
+      var found = findCookie (cookie).ToList ();
+
+      if (found.Count == 0)
+        return true;
+
+      var ver = cookie.Version;
+
+      foreach (var c in found) {
+        if (c.Version == ver)
+          return true;
+      }
+
+      return false;
+    }
+
+    private void close (bool force)
+    {
+      _disposed = true;
+      _context.Connection.Close (force);
+    }
+
+    private void close (byte[] responseEntity, int bufferLength, bool willBlock)
+    {
+      var stream = OutputStream;
+
+      if (willBlock) {
+        stream.WriteBytes (responseEntity, bufferLength);
+        close (false);
+
+        return;
+      }
+
+      stream.WriteBytesAsync (
+        responseEntity,
+        bufferLength,
+        () => close (false),
+        null
+      );
+    }
+
+    private static string createContentTypeHeaderText (
+      string value, Encoding encoding
+    )
+    {
+      if (value.IndexOf ("charset=", StringComparison.Ordinal) > -1)
+        return value;
+
+      if (encoding == null)
+        return value;
+
+      return String.Format ("{0}; charset={1}", value, encoding.WebName);
+    }
+
+    private IEnumerable<Cookie> findCookie (Cookie cookie)
+    {
+      if (_cookies == null || _cookies.Count == 0)
+        yield break;
+
+      foreach (var c in _cookies) {
+        if (c.EqualsWithoutValueAndVersion (cookie))
+          yield return c;
+      }
+    }
+
+    private static bool isValidForContentType (string value)
+    {
+      foreach (var c in value) {
+        if (c < 0x20)
+          return false;
+
+        if (c > 0x7e)
+          return false;
+
+        if ("()<>@:\\[]?{}".IndexOf (c) > -1)
+          return false;
+      }
+
+      return true;
+    }
+
+    private static bool isValidForStatusDescription (string value)
+    {
+      foreach (var c in value) {
+        if (c < 0x20)
+          return false;
+
+        if (c > 0x7e)
+          return false;
+      }
+
+      return true;
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    /// <summary>
+    /// Closes the connection to the client without sending a response.
+    /// </summary>
+    public void Abort ()
+    {
+      if (_disposed)
+        return;
+
+      close (true);
+    }
+
+    /// <summary>
+    /// Appends the specified cookie to the cookies sent with the response.
+    /// </summary>
+    /// <param name="cookie">
+    /// A <see cref="Cookie"/> to append.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="cookie"/> is <see langword="null"/>.
+    /// </exception>
+    public void AppendCookie (Cookie cookie)
+    {
+      Cookies.Add (cookie);
+    }
+
+    /// <summary>
+    /// Appends an HTTP header with the specified name and value to
+    /// the headers for the response.
+    /// </summary>
+    /// <param name="name">
+    /// A <see cref="string"/> that specifies the name of the header to
+    /// append.
+    /// </param>
+    /// <param name="value">
+    /// A <see cref="string"/> that specifies the value of the header to
+    /// append.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="name"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   <paramref name="name"/> is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> is a string of spaces.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="value"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> is a restricted header name.
+    ///   </para>
+    /// </exception>
+    /// <exception cref="ArgumentOutOfRangeException">
+    /// The length of <paramref name="value"/> is greater than 65,535
+    /// characters.
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The current headers do not allow the header.
+    /// </exception>
+    public void AppendHeader (string name, string value)
+    {
+      Headers.Add (name, value);
+    }
+
+    /// <summary>
+    /// Sends the response to the client and releases the resources used by
+    /// this instance.
+    /// </summary>
+    public void Close ()
+    {
+      if (_disposed)
+        return;
+
+      close (false);
+    }
+
+    /// <summary>
+    /// Sends the response with the specified entity body data to the client
+    /// and releases the resources used by this instance.
+    /// </summary>
+    /// <param name="responseEntity">
+    /// An array of <see cref="byte"/> that contains the entity body data.
+    /// </param>
+    /// <param name="willBlock">
+    /// A <see cref="bool"/>: <c>true</c> if this method blocks execution while
+    /// flushing the stream to the client; otherwise, <c>false</c>.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="responseEntity"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public void Close (byte[] responseEntity, bool willBlock)
+    {
+      if (_disposed) {
+        var name = GetType ().ToString ();
+        throw new ObjectDisposedException (name);
+      }
+
+      if (responseEntity == null)
+        throw new ArgumentNullException ("responseEntity");
+
+      var len = responseEntity.LongLength;
+
+      if (len > Int32.MaxValue) {
+        close (responseEntity, 1024, willBlock);
+        return;
+      }
+
+      var stream = OutputStream;
+
+      if (willBlock) {
+        stream.Write (responseEntity, 0, (int) len);
+        close (false);
+
+        return;
+      }
+
+      stream.BeginWrite (
+        responseEntity,
+        0,
+        (int) len,
+        ar => {
+          stream.EndWrite (ar);
+          close (false);
+        },
+        null
+      );
+    }
+
+    /// <summary>
+    /// Copies some properties from the specified response instance to
+    /// this instance.
+    /// </summary>
+    /// <param name="templateResponse">
+    /// A <see cref="HttpListenerResponse"/> to copy.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="templateResponse"/> is <see langword="null"/>.
+    /// </exception>
+    public void CopyFrom (HttpListenerResponse templateResponse)
+    {
+      if (templateResponse == null)
+        throw new ArgumentNullException ("templateResponse");
+
+      var headers = templateResponse._headers;
+
+      if (headers != null) {
+        if (_headers != null)
+          _headers.Clear ();
+
+        Headers.Add (headers);
+      }
+      else {
+        _headers = null;
+      }
+
+      _contentLength = templateResponse._contentLength;
+      _statusCode = templateResponse._statusCode;
+      _statusDescription = templateResponse._statusDescription;
+      _keepAlive = templateResponse._keepAlive;
+      _version = templateResponse._version;
+    }
+
+    /// <summary>
+    /// Configures the response to redirect the client's request to
+    /// the specified URL.
+    /// </summary>
+    /// <remarks>
+    /// This method sets the <see cref="RedirectLocation"/> property to
+    /// <paramref name="url"/>, the <see cref="StatusCode"/> property to
+    /// 302, and the <see cref="StatusDescription"/> property to "Found".
+    /// </remarks>
+    /// <param name="url">
+    /// A <see cref="string"/> that specifies the absolute URL to which
+    /// the client is redirected to locate a requested resource.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="url"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   <paramref name="url"/> is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="url"/> is not an absolute URL.
+    ///   </para>
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The response is already being sent.
+    /// </exception>
+    /// <exception cref="ObjectDisposedException">
+    /// This instance is closed.
+    /// </exception>
+    public void Redirect (string url)
+    {
+      if (_disposed) {
+        var name = GetType ().ToString ();
+        throw new ObjectDisposedException (name);
+      }
+
+      if (_headersSent) {
+        var msg = "The response is already being sent.";
+        throw new InvalidOperationException (msg);
+      }
+
+      if (url == null)
+        throw new ArgumentNullException ("url");
+
+      if (url.Length == 0) {
+        var msg = "An empty string.";
+        throw new ArgumentException (msg, "url");
+      }
+
+      Uri uri;
+      if (!Uri.TryCreate (url, UriKind.Absolute, out uri)) {
+        var msg = "Not an absolute URL.";
+        throw new ArgumentException (msg, "url");
+      }
+
+      _redirectLocation = uri;
+      _statusCode = 302;
+      _statusDescription = "Found";
+    }
+
+    /// <summary>
+    /// Adds or updates a cookie in the cookies sent with the response.
+    /// </summary>
+    /// <param name="cookie">
+    /// A <see cref="Cookie"/> to set.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="cookie"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    /// <paramref name="cookie"/> already exists in the cookies but
+    /// it cannot be updated.
+    /// </exception>
+    public void SetCookie (Cookie cookie)
+    {
+      if (cookie == null)
+        throw new ArgumentNullException ("cookie");
+
+      if (!canSetCookie (cookie)) {
+        var msg = "It cannot be updated.";
+        throw new ArgumentException (msg, "cookie");
+      }
+
+      Cookies.Add (cookie);
+    }
+
+    /// <summary>
+    /// Adds or updates an HTTP header with the specified name and value in
+    /// the headers for the response.
+    /// </summary>
+    /// <param name="name">
+    /// A <see cref="string"/> that specifies the name of the header to set.
+    /// </param>
+    /// <param name="value">
+    /// A <see cref="string"/> that specifies the value of the header to set.
+    /// </param>
+    /// <exception cref="ArgumentNullException">
+    /// <paramref name="name"/> is <see langword="null"/>.
+    /// </exception>
+    /// <exception cref="ArgumentException">
+    ///   <para>
+    ///   <paramref name="name"/> is an empty string.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> is a string of spaces.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="value"/> contains an invalid character.
+    ///   </para>
+    ///   <para>
+    ///   -or-
+    ///   </para>
+    ///   <para>
+    ///   <paramref name="name"/> is a restricted header name.
+    ///   </para>
+    /// </exception>
+    /// <exception cref="ArgumentOutOfRangeException">
+    /// The length of <paramref name="value"/> is greater than 65,535
+    /// characters.
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    /// The current headers do not allow the header.
+    /// </exception>
+    public void SetHeader (string name, string value)
+    {
+      Headers.Set (name, value);
+    }
+
+    #endregion
+
+    #region Explicit Interface Implementations
+
+    /// <summary>
+    /// Releases all resources used by this instance.
+    /// </summary>
+    void IDisposable.Dispose ()
+    {
+      if (_disposed)
+        return;
+
+      close (true);
+    }
+
+    #endregion
+  }
+}

+ 233 - 0
src/websocket-sharp/Net/HttpRequestHeader.cs

@@ -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 <[email protected]>
+ */
+#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 - 0
src/websocket-sharp/Net/HttpResponseHeader.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 346 - 0
src/websocket-sharp/Net/HttpStatusCode.cs

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

+ 184 - 0
src/websocket-sharp/Net/HttpStreamAsyncResult.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 1150 - 0
src/websocket-sharp/Net/HttpUtility.cs

@@ -0,0 +1,1150 @@
+#region License
+/*
+ * HttpUtility.cs
+ *
+ * This code is derived from HttpUtility.cs (System.Net) of Mono
+ * (http://www.mono-project.com).
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2005-2009 Novell, Inc. (http://www.novell.com)
+ * Copyright (c) 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:
+ * - Patrik Torstensson <[email protected]>
+ * - Wictor Wilén (decode/encode functions) <[email protected]>
+ * - Tim Coleman <[email protected]>
+ * - Gonzalo Paniagua Javier <[email protected]>
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Security.Principal;
+using System.Text;
+
+namespace WebSocketSharp.Net
+{
+  internal static class HttpUtility
+  {
+    #region Private Fields
+
+    private static Dictionary<string, char> _entities;
+    private static char[]                   _hexChars;
+    private static object                   _sync;
+
+    #endregion
+
+    #region Static Constructor
+
+    static HttpUtility ()
+    {
+      _hexChars = "0123456789ABCDEF".ToCharArray ();
+      _sync = new object ();
+    }
+
+    #endregion
+
+    #region Private Methods
+
+    private static Dictionary<string, char> getEntities ()
+    {
+      lock (_sync) {
+        if (_entities == null)
+          initEntities ();
+
+        return _entities;
+      }
+    }
+
+    private static int getNumber (char c)
+    {
+      return c >= '0' && c <= '9'
+             ? c - '0'
+             : c >= 'A' && c <= 'F'
+               ? c - 'A' + 10
+               : c >= 'a' && c <= 'f'
+                 ? c - 'a' + 10
+                 : -1;
+    }
+
+    private static int getNumber (byte[] bytes, int offset, int count)
+    {
+      var ret = 0;
+
+      var end = offset + count - 1;
+      for (var i = offset; i <= end; i++) {
+        var num = getNumber ((char) bytes[i]);
+        if (num == -1)
+          return -1;
+
+        ret = (ret << 4) + num;
+      }
+
+      return ret;
+    }
+
+    private static int getNumber (string s, int offset, int count)
+    {
+      var ret = 0;
+
+      var end = offset + count - 1;
+      for (var i = offset; i <= end; i++) {
+        var num = getNumber (s[i]);
+        if (num == -1)
+          return -1;
+
+        ret = (ret << 4) + num;
+      }
+
+      return ret;
+    }
+
+    private static string htmlDecode (string s)
+    {
+      var buff = new StringBuilder ();
+
+      // 0: None
+      // 1: Right after '&'
+      // 2: Between '&' and ';' but no NCR
+      // 3: '#' found after '&' and getting numbers
+      // 4: 'x' found after '#' and getting numbers
+      var state = 0;
+
+      var reference = new StringBuilder ();
+      var num = 0;
+
+      foreach (var c in s) {
+        if (state == 0) {
+          if (c == '&') {
+            reference.Append ('&');
+            state = 1;
+
+            continue;
+          }
+
+          buff.Append (c);
+          continue;
+        }
+
+        if (c == '&') {
+          buff.Append (reference.ToString ());
+
+          reference.Length = 0;
+          reference.Append ('&');
+          state = 1;
+
+          continue;
+        }
+
+        reference.Append (c);
+
+        if (state == 1) {
+          if (c == ';') {
+            buff.Append (reference.ToString ());
+
+            reference.Length = 0;
+            state = 0;
+
+            continue;
+          }
+
+          num = 0;
+          state = c == '#' ? 3 : 2;
+
+          continue;
+        }
+
+        if (state == 2) {
+          if (c == ';') {
+            var entity = reference.ToString ();
+            var name = entity.Substring (1, entity.Length - 2);
+
+            var entities = getEntities ();
+            if (entities.ContainsKey (name))
+              buff.Append (entities[name]);
+            else
+              buff.Append (entity);
+
+            reference.Length = 0;
+            state = 0;
+
+            continue;
+          }
+
+          continue;
+        }
+
+        if (state == 3) {
+          if (c == ';') {
+            if (reference.Length > 3 && num < 65536)
+              buff.Append ((char) num);
+            else
+              buff.Append (reference.ToString ());
+
+            reference.Length = 0;
+            state = 0;
+
+            continue;
+          }
+
+          if (c == 'x') {
+            state = reference.Length == 3 ? 4 : 2;
+            continue;
+          }
+
+          if (!isNumeric (c)) {
+            state = 2;
+            continue;
+          }
+
+          num = num * 10 + (c - '0');
+          continue;
+        }
+
+        if (state == 4) {
+          if (c == ';') {
+            if (reference.Length > 4 && num < 65536)
+              buff.Append ((char) num);
+            else
+              buff.Append (reference.ToString ());
+
+            reference.Length = 0;
+            state = 0;
+
+            continue;
+          }
+
+          var n = getNumber (c);
+          if (n == -1) {
+            state = 2;
+            continue;
+          }
+
+          num = (num << 4) + n;
+        }
+      }
+
+      if (reference.Length > 0)
+        buff.Append (reference.ToString ());
+
+      return buff.ToString ();
+    }
+
+    /// <summary>
+    /// Converts the specified string to an HTML-encoded string.
+    /// </summary>
+    /// <remarks>
+    ///   <para>
+    ///   This method starts encoding with a NCR from the character code 160
+    ///   but does not stop at the character code 255.
+    ///   </para>
+    ///   <para>
+    ///   One reason is the unicode characters &#65308; and &#65310; that
+    ///   look like &lt; and &gt;.
+    ///   </para>
+    /// </remarks>
+    /// <returns>
+    /// A <see cref="string"/> that represents an encoded string.
+    /// </returns>
+    /// <param name="s">
+    /// A <see cref="string"/> to encode.
+    /// </param>
+    /// <param name="minimal">
+    /// A <see cref="bool"/>: <c>true</c> if encodes without a NCR;
+    /// otherwise, <c>false</c>.
+    /// </param>
+    private static string htmlEncode (string s, bool minimal)
+    {
+      var buff = new StringBuilder ();
+
+      foreach (var c in s) {
+        buff.Append (
+          c == '"'
+          ? "&quot;"
+          : c == '&'
+            ? "&amp;"
+            : c == '<'
+              ? "&lt;"
+              : c == '>'
+                ? "&gt;"
+                : !minimal && c > 159
+                  ? String.Format ("&#{0};", (int) c)
+                  : c.ToString ()
+        );
+      }
+
+      return buff.ToString ();
+    }
+
+    /// <summary>
+    /// Initializes the _entities field.
+    /// </summary>
+    /// <remarks>
+    /// This method builds a dictionary of HTML character entity references.
+    /// This dictionary comes from the HTML 4.01 W3C recommendation.
+    /// </remarks>
+    private static void initEntities ()
+    {
+      _entities = new Dictionary<string, char> ();
+      _entities.Add ("nbsp", '\u00A0');
+      _entities.Add ("iexcl", '\u00A1');
+      _entities.Add ("cent", '\u00A2');
+      _entities.Add ("pound", '\u00A3');
+      _entities.Add ("curren", '\u00A4');
+      _entities.Add ("yen", '\u00A5');
+      _entities.Add ("brvbar", '\u00A6');
+      _entities.Add ("sect", '\u00A7');
+      _entities.Add ("uml", '\u00A8');
+      _entities.Add ("copy", '\u00A9');
+      _entities.Add ("ordf", '\u00AA');
+      _entities.Add ("laquo", '\u00AB');
+      _entities.Add ("not", '\u00AC');
+      _entities.Add ("shy", '\u00AD');
+      _entities.Add ("reg", '\u00AE');
+      _entities.Add ("macr", '\u00AF');
+      _entities.Add ("deg", '\u00B0');
+      _entities.Add ("plusmn", '\u00B1');
+      _entities.Add ("sup2", '\u00B2');
+      _entities.Add ("sup3", '\u00B3');
+      _entities.Add ("acute", '\u00B4');
+      _entities.Add ("micro", '\u00B5');
+      _entities.Add ("para", '\u00B6');
+      _entities.Add ("middot", '\u00B7');
+      _entities.Add ("cedil", '\u00B8');
+      _entities.Add ("sup1", '\u00B9');
+      _entities.Add ("ordm", '\u00BA');
+      _entities.Add ("raquo", '\u00BB');
+      _entities.Add ("frac14", '\u00BC');
+      _entities.Add ("frac12", '\u00BD');
+      _entities.Add ("frac34", '\u00BE');
+      _entities.Add ("iquest", '\u00BF');
+      _entities.Add ("Agrave", '\u00C0');
+      _entities.Add ("Aacute", '\u00C1');
+      _entities.Add ("Acirc", '\u00C2');
+      _entities.Add ("Atilde", '\u00C3');
+      _entities.Add ("Auml", '\u00C4');
+      _entities.Add ("Aring", '\u00C5');
+      _entities.Add ("AElig", '\u00C6');
+      _entities.Add ("Ccedil", '\u00C7');
+      _entities.Add ("Egrave", '\u00C8');
+      _entities.Add ("Eacute", '\u00C9');
+      _entities.Add ("Ecirc", '\u00CA');
+      _entities.Add ("Euml", '\u00CB');
+      _entities.Add ("Igrave", '\u00CC');
+      _entities.Add ("Iacute", '\u00CD');
+      _entities.Add ("Icirc", '\u00CE');
+      _entities.Add ("Iuml", '\u00CF');
+      _entities.Add ("ETH", '\u00D0');
+      _entities.Add ("Ntilde", '\u00D1');
+      _entities.Add ("Ograve", '\u00D2');
+      _entities.Add ("Oacute", '\u00D3');
+      _entities.Add ("Ocirc", '\u00D4');
+      _entities.Add ("Otilde", '\u00D5');
+      _entities.Add ("Ouml", '\u00D6');
+      _entities.Add ("times", '\u00D7');
+      _entities.Add ("Oslash", '\u00D8');
+      _entities.Add ("Ugrave", '\u00D9');
+      _entities.Add ("Uacute", '\u00DA');
+      _entities.Add ("Ucirc", '\u00DB');
+      _entities.Add ("Uuml", '\u00DC');
+      _entities.Add ("Yacute", '\u00DD');
+      _entities.Add ("THORN", '\u00DE');
+      _entities.Add ("szlig", '\u00DF');
+      _entities.Add ("agrave", '\u00E0');
+      _entities.Add ("aacute", '\u00E1');
+      _entities.Add ("acirc", '\u00E2');
+      _entities.Add ("atilde", '\u00E3');
+      _entities.Add ("auml", '\u00E4');
+      _entities.Add ("aring", '\u00E5');
+      _entities.Add ("aelig", '\u00E6');
+      _entities.Add ("ccedil", '\u00E7');
+      _entities.Add ("egrave", '\u00E8');
+      _entities.Add ("eacute", '\u00E9');
+      _entities.Add ("ecirc", '\u00EA');
+      _entities.Add ("euml", '\u00EB');
+      _entities.Add ("igrave", '\u00EC');
+      _entities.Add ("iacute", '\u00ED');
+      _entities.Add ("icirc", '\u00EE');
+      _entities.Add ("iuml", '\u00EF');
+      _entities.Add ("eth", '\u00F0');
+      _entities.Add ("ntilde", '\u00F1');
+      _entities.Add ("ograve", '\u00F2');
+      _entities.Add ("oacute", '\u00F3');
+      _entities.Add ("ocirc", '\u00F4');
+      _entities.Add ("otilde", '\u00F5');
+      _entities.Add ("ouml", '\u00F6');
+      _entities.Add ("divide", '\u00F7');
+      _entities.Add ("oslash", '\u00F8');
+      _entities.Add ("ugrave", '\u00F9');
+      _entities.Add ("uacute", '\u00FA');
+      _entities.Add ("ucirc", '\u00FB');
+      _entities.Add ("uuml", '\u00FC');
+      _entities.Add ("yacute", '\u00FD');
+      _entities.Add ("thorn", '\u00FE');
+      _entities.Add ("yuml", '\u00FF');
+      _entities.Add ("fnof", '\u0192');
+      _entities.Add ("Alpha", '\u0391');
+      _entities.Add ("Beta", '\u0392');
+      _entities.Add ("Gamma", '\u0393');
+      _entities.Add ("Delta", '\u0394');
+      _entities.Add ("Epsilon", '\u0395');
+      _entities.Add ("Zeta", '\u0396');
+      _entities.Add ("Eta", '\u0397');
+      _entities.Add ("Theta", '\u0398');
+      _entities.Add ("Iota", '\u0399');
+      _entities.Add ("Kappa", '\u039A');
+      _entities.Add ("Lambda", '\u039B');
+      _entities.Add ("Mu", '\u039C');
+      _entities.Add ("Nu", '\u039D');
+      _entities.Add ("Xi", '\u039E');
+      _entities.Add ("Omicron", '\u039F');
+      _entities.Add ("Pi", '\u03A0');
+      _entities.Add ("Rho", '\u03A1');
+      _entities.Add ("Sigma", '\u03A3');
+      _entities.Add ("Tau", '\u03A4');
+      _entities.Add ("Upsilon", '\u03A5');
+      _entities.Add ("Phi", '\u03A6');
+      _entities.Add ("Chi", '\u03A7');
+      _entities.Add ("Psi", '\u03A8');
+      _entities.Add ("Omega", '\u03A9');
+      _entities.Add ("alpha", '\u03B1');
+      _entities.Add ("beta", '\u03B2');
+      _entities.Add ("gamma", '\u03B3');
+      _entities.Add ("delta", '\u03B4');
+      _entities.Add ("epsilon", '\u03B5');
+      _entities.Add ("zeta", '\u03B6');
+      _entities.Add ("eta", '\u03B7');
+      _entities.Add ("theta", '\u03B8');
+      _entities.Add ("iota", '\u03B9');
+      _entities.Add ("kappa", '\u03BA');
+      _entities.Add ("lambda", '\u03BB');
+      _entities.Add ("mu", '\u03BC');
+      _entities.Add ("nu", '\u03BD');
+      _entities.Add ("xi", '\u03BE');
+      _entities.Add ("omicron", '\u03BF');
+      _entities.Add ("pi", '\u03C0');
+      _entities.Add ("rho", '\u03C1');
+      _entities.Add ("sigmaf", '\u03C2');
+      _entities.Add ("sigma", '\u03C3');
+      _entities.Add ("tau", '\u03C4');
+      _entities.Add ("upsilon", '\u03C5');
+      _entities.Add ("phi", '\u03C6');
+      _entities.Add ("chi", '\u03C7');
+      _entities.Add ("psi", '\u03C8');
+      _entities.Add ("omega", '\u03C9');
+      _entities.Add ("thetasym", '\u03D1');
+      _entities.Add ("upsih", '\u03D2');
+      _entities.Add ("piv", '\u03D6');
+      _entities.Add ("bull", '\u2022');
+      _entities.Add ("hellip", '\u2026');
+      _entities.Add ("prime", '\u2032');
+      _entities.Add ("Prime", '\u2033');
+      _entities.Add ("oline", '\u203E');
+      _entities.Add ("frasl", '\u2044');
+      _entities.Add ("weierp", '\u2118');
+      _entities.Add ("image", '\u2111');
+      _entities.Add ("real", '\u211C');
+      _entities.Add ("trade", '\u2122');
+      _entities.Add ("alefsym", '\u2135');
+      _entities.Add ("larr", '\u2190');
+      _entities.Add ("uarr", '\u2191');
+      _entities.Add ("rarr", '\u2192');
+      _entities.Add ("darr", '\u2193');
+      _entities.Add ("harr", '\u2194');
+      _entities.Add ("crarr", '\u21B5');
+      _entities.Add ("lArr", '\u21D0');
+      _entities.Add ("uArr", '\u21D1');
+      _entities.Add ("rArr", '\u21D2');
+      _entities.Add ("dArr", '\u21D3');
+      _entities.Add ("hArr", '\u21D4');
+      _entities.Add ("forall", '\u2200');
+      _entities.Add ("part", '\u2202');
+      _entities.Add ("exist", '\u2203');
+      _entities.Add ("empty", '\u2205');
+      _entities.Add ("nabla", '\u2207');
+      _entities.Add ("isin", '\u2208');
+      _entities.Add ("notin", '\u2209');
+      _entities.Add ("ni", '\u220B');
+      _entities.Add ("prod", '\u220F');
+      _entities.Add ("sum", '\u2211');
+      _entities.Add ("minus", '\u2212');
+      _entities.Add ("lowast", '\u2217');
+      _entities.Add ("radic", '\u221A');
+      _entities.Add ("prop", '\u221D');
+      _entities.Add ("infin", '\u221E');
+      _entities.Add ("ang", '\u2220');
+      _entities.Add ("and", '\u2227');
+      _entities.Add ("or", '\u2228');
+      _entities.Add ("cap", '\u2229');
+      _entities.Add ("cup", '\u222A');
+      _entities.Add ("int", '\u222B');
+      _entities.Add ("there4", '\u2234');
+      _entities.Add ("sim", '\u223C');
+      _entities.Add ("cong", '\u2245');
+      _entities.Add ("asymp", '\u2248');
+      _entities.Add ("ne", '\u2260');
+      _entities.Add ("equiv", '\u2261');
+      _entities.Add ("le", '\u2264');
+      _entities.Add ("ge", '\u2265');
+      _entities.Add ("sub", '\u2282');
+      _entities.Add ("sup", '\u2283');
+      _entities.Add ("nsub", '\u2284');
+      _entities.Add ("sube", '\u2286');
+      _entities.Add ("supe", '\u2287');
+      _entities.Add ("oplus", '\u2295');
+      _entities.Add ("otimes", '\u2297');
+      _entities.Add ("perp", '\u22A5');
+      _entities.Add ("sdot", '\u22C5');
+      _entities.Add ("lceil", '\u2308');
+      _entities.Add ("rceil", '\u2309');
+      _entities.Add ("lfloor", '\u230A');
+      _entities.Add ("rfloor", '\u230B');
+      _entities.Add ("lang", '\u2329');
+      _entities.Add ("rang", '\u232A');
+      _entities.Add ("loz", '\u25CA');
+      _entities.Add ("spades", '\u2660');
+      _entities.Add ("clubs", '\u2663');
+      _entities.Add ("hearts", '\u2665');
+      _entities.Add ("diams", '\u2666');
+      _entities.Add ("quot", '\u0022');
+      _entities.Add ("amp", '\u0026');
+      _entities.Add ("lt", '\u003C');
+      _entities.Add ("gt", '\u003E');
+      _entities.Add ("OElig", '\u0152');
+      _entities.Add ("oelig", '\u0153');
+      _entities.Add ("Scaron", '\u0160');
+      _entities.Add ("scaron", '\u0161');
+      _entities.Add ("Yuml", '\u0178');
+      _entities.Add ("circ", '\u02C6');
+      _entities.Add ("tilde", '\u02DC');
+      _entities.Add ("ensp", '\u2002');
+      _entities.Add ("emsp", '\u2003');
+      _entities.Add ("thinsp", '\u2009');
+      _entities.Add ("zwnj", '\u200C');
+      _entities.Add ("zwj", '\u200D');
+      _entities.Add ("lrm", '\u200E');
+      _entities.Add ("rlm", '\u200F');
+      _entities.Add ("ndash", '\u2013');
+      _entities.Add ("mdash", '\u2014');
+      _entities.Add ("lsquo", '\u2018');
+      _entities.Add ("rsquo", '\u2019');
+      _entities.Add ("sbquo", '\u201A');
+      _entities.Add ("ldquo", '\u201C');
+      _entities.Add ("rdquo", '\u201D');
+      _entities.Add ("bdquo", '\u201E');
+      _entities.Add ("dagger", '\u2020');
+      _entities.Add ("Dagger", '\u2021');
+      _entities.Add ("permil", '\u2030');
+      _entities.Add ("lsaquo", '\u2039');
+      _entities.Add ("rsaquo", '\u203A');
+      _entities.Add ("euro", '\u20AC');
+    }
+
+    private static bool isAlphabet (char c)
+    {
+      return (c >= 'A' && c <= 'Z')
+             || (c >= 'a' && c <= 'z');
+    }
+
+    private static bool isNumeric (char c)
+    {
+      return c >= '0' && c <= '9';
+    }
+
+    private static bool isUnreserved (char c)
+    {
+      return c == '*'
+             || c == '-'
+             || c == '.'
+             || c == '_';
+    }
+
+    private static bool isUnreservedInRfc2396 (char c)
+    {
+      return c == '!'
+             || c == '\''
+             || c == '('
+             || c == ')'
+             || c == '*'
+             || c == '-'
+             || c == '.'
+             || c == '_'
+             || c == '~';
+    }
+
+    private static bool isUnreservedInRfc3986 (char c)
+    {
+      return c == '-'
+             || c == '.'
+             || c == '_'
+             || c == '~';
+    }
+
+    private static byte[] urlDecodeToBytes (byte[] bytes, int offset, int count)
+    {
+      using (var buff = new MemoryStream ()) {
+        var end = offset + count - 1;
+        for (var i = offset; i <= end; i++) {
+          var b = bytes[i];
+
+          var c = (char) b;
+          if (c == '%') {
+            if (i > end - 2)
+              break;
+
+            var num = getNumber (bytes, i + 1, 2);
+            if (num == -1)
+              break;
+
+            buff.WriteByte ((byte) num);
+            i += 2;
+
+            continue;
+          }
+
+          if (c == '+') {
+            buff.WriteByte ((byte) ' ');
+            continue;
+          }
+
+          buff.WriteByte (b);
+        }
+
+        buff.Close ();
+        return buff.ToArray ();
+      }
+    }
+
+    private static void urlEncode (byte b, Stream output)
+    {
+      if (b > 31 && b < 127) {
+        var c = (char) b;
+        if (c == ' ') {
+          output.WriteByte ((byte) '+');
+          return;
+        }
+
+        if (isNumeric (c)) {
+          output.WriteByte (b);
+          return;
+        }
+
+        if (isAlphabet (c)) {
+          output.WriteByte (b);
+          return;
+        }
+
+        if (isUnreserved (c)) {
+          output.WriteByte (b);
+          return;
+        }
+      }
+
+      var i = (int) b;
+      var bytes = new byte[] {
+                    (byte) '%',
+                    (byte) _hexChars[i >> 4],
+                    (byte) _hexChars[i & 0x0F]
+                  };
+
+      output.Write (bytes, 0, 3);
+    }
+
+    private static byte[] urlEncodeToBytes (byte[] bytes, int offset, int count)
+    {
+      using (var buff = new MemoryStream ()) {
+        var end = offset + count - 1;
+        for (var i = offset; i <= end; i++)
+          urlEncode (bytes[i], buff);
+
+        buff.Close ();
+        return buff.ToArray ();
+      }
+    }
+
+    #endregion
+
+    #region Internal Methods
+
+    internal static Uri CreateRequestUrl (
+      string requestUri, string host, bool websocketRequest, bool secure
+    )
+    {
+      if (requestUri == null || requestUri.Length == 0)
+        return null;
+
+      if (host == null || host.Length == 0)
+        return null;
+
+      string schm = null;
+      string path = null;
+
+      if (requestUri.IndexOf ('/') == 0) {
+        path = requestUri;
+      }
+      else if (requestUri.MaybeUri ()) {
+        Uri uri;
+
+        if (!Uri.TryCreate (requestUri, UriKind.Absolute, out uri))
+          return null;
+
+        schm = uri.Scheme;
+        var valid = websocketRequest
+                    ? schm == "ws" || schm == "wss"
+                    : schm == "http" || schm == "https";
+
+        if (!valid)
+          return null;
+
+        host = uri.Authority;
+        path = uri.PathAndQuery;
+      }
+      else if (requestUri == "*") {
+      }
+      else {
+        // As the authority form.
+
+        host = requestUri;
+      }
+
+      if (schm == null) {
+        schm = websocketRequest
+               ? (secure ? "wss" : "ws")
+               : (secure ? "https" : "http");
+      }
+
+      if (host.IndexOf (':') == -1)
+        host = String.Format ("{0}:{1}", host, secure ? 443 : 80);
+
+      var url = String.Format ("{0}://{1}{2}", schm, host, path);
+      Uri ret;
+
+      return Uri.TryCreate (url, UriKind.Absolute, out ret) ? ret : null;
+    }
+
+    internal static IPrincipal CreateUser (
+      string response,
+      AuthenticationSchemes scheme,
+      string realm,
+      string method,
+      Func<IIdentity, NetworkCredential> credentialsFinder
+    )
+    {
+      if (response == null || response.Length == 0)
+        return null;
+
+      if (scheme == AuthenticationSchemes.Digest) {
+        if (realm == null || realm.Length == 0)
+          return null;
+
+        if (method == null || method.Length == 0)
+          return null;
+      }
+      else {
+        if (scheme != AuthenticationSchemes.Basic)
+          return null;
+      }
+
+      if (credentialsFinder == null)
+        return null;
+
+      var compType = StringComparison.OrdinalIgnoreCase;
+      if (response.IndexOf (scheme.ToString (), compType) != 0)
+        return null;
+
+      var res = AuthenticationResponse.Parse (response);
+      if (res == null)
+        return null;
+
+      var id = res.ToIdentity ();
+      if (id == null)
+        return null;
+
+      NetworkCredential cred = null;
+      try {
+        cred = credentialsFinder (id);
+      }
+      catch {
+      }
+
+      if (cred == null)
+        return null;
+
+      if (scheme == AuthenticationSchemes.Basic) {
+        var basicId = (HttpBasicIdentity) id;
+        return basicId.Password == cred.Password
+               ? new GenericPrincipal (id, cred.Roles)
+               : null;
+      }
+
+      var digestId = (HttpDigestIdentity) id;
+      return digestId.IsValid (cred.Password, realm, method, null)
+             ? new GenericPrincipal (id, cred.Roles)
+             : null;
+    }
+
+    internal static Encoding GetEncoding (string contentType)
+    {
+      var name = "charset=";
+      var compType = StringComparison.OrdinalIgnoreCase;
+
+      foreach (var elm in contentType.SplitHeaderValue (';')) {
+        var part = elm.Trim ();
+
+        if (!part.StartsWith (name, compType))
+          continue;
+
+        var val = part.GetValue ('=', true);
+
+        if (val == null || val.Length == 0)
+          return null;
+
+        return Encoding.GetEncoding (val);
+      }
+
+      return null;
+    }
+
+    internal static bool TryGetEncoding (
+      string contentType, out Encoding result
+    )
+    {
+      result = null;
+
+      try {
+        result = GetEncoding (contentType);
+      }
+      catch {
+        return false;
+      }
+
+      return result != null;
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    public static string HtmlAttributeEncode (string s)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      return s.Length > 0 ? htmlEncode (s, true) : s;
+    }
+
+    public static void HtmlAttributeEncode (string s, TextWriter output)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      if (output == null)
+        throw new ArgumentNullException ("output");
+
+      if (s.Length == 0)
+        return;
+
+      output.Write (htmlEncode (s, true));
+    }
+
+    public static string HtmlDecode (string s)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      return s.Length > 0 ? htmlDecode (s) : s;
+    }
+
+    public static void HtmlDecode (string s, TextWriter output)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      if (output == null)
+        throw new ArgumentNullException ("output");
+
+      if (s.Length == 0)
+        return;
+
+      output.Write (htmlDecode (s));
+    }
+
+    public static string HtmlEncode (string s)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      return s.Length > 0 ? htmlEncode (s, false) : s;
+    }
+
+    public static void HtmlEncode (string s, TextWriter output)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      if (output == null)
+        throw new ArgumentNullException ("output");
+
+      if (s.Length == 0)
+        return;
+
+      output.Write (htmlEncode (s, false));
+    }
+
+    public static string UrlDecode (string s)
+    {
+      return UrlDecode (s, Encoding.UTF8);
+    }
+
+    public static string UrlDecode (byte[] bytes, Encoding encoding)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      return len > 0
+             ? (encoding ?? Encoding.UTF8).GetString (
+                 urlDecodeToBytes (bytes, 0, len)
+               )
+             : String.Empty;
+    }
+
+    public static string UrlDecode (string s, Encoding encoding)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      if (s.Length == 0)
+        return s;
+
+      var bytes = Encoding.ASCII.GetBytes (s);
+      return (encoding ?? Encoding.UTF8).GetString (
+               urlDecodeToBytes (bytes, 0, bytes.Length)
+             );
+    }
+
+    public static string UrlDecode (
+      byte[] bytes, int offset, int count, Encoding encoding
+    )
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      if (len == 0) {
+        if (offset != 0)
+          throw new ArgumentOutOfRangeException ("offset");
+
+        if (count != 0)
+          throw new ArgumentOutOfRangeException ("count");
+
+        return String.Empty;
+      }
+
+      if (offset < 0 || offset >= len)
+        throw new ArgumentOutOfRangeException ("offset");
+
+      if (count < 0 || count > len - offset)
+        throw new ArgumentOutOfRangeException ("count");
+
+      return count > 0
+             ? (encoding ?? Encoding.UTF8).GetString (
+                 urlDecodeToBytes (bytes, offset, count)
+               )
+             : String.Empty;
+    }
+
+    public static byte[] UrlDecodeToBytes (byte[] bytes)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      return len > 0
+             ? urlDecodeToBytes (bytes, 0, len)
+             : bytes;
+    }
+
+    public static byte[] UrlDecodeToBytes (string s)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      if (s.Length == 0)
+        return new byte[0];
+
+      var bytes = Encoding.ASCII.GetBytes (s);
+      return urlDecodeToBytes (bytes, 0, bytes.Length);
+    }
+
+    public static byte[] UrlDecodeToBytes (byte[] bytes, int offset, int count)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      if (len == 0) {
+        if (offset != 0)
+          throw new ArgumentOutOfRangeException ("offset");
+
+        if (count != 0)
+          throw new ArgumentOutOfRangeException ("count");
+
+        return bytes;
+      }
+
+      if (offset < 0 || offset >= len)
+        throw new ArgumentOutOfRangeException ("offset");
+
+      if (count < 0 || count > len - offset)
+        throw new ArgumentOutOfRangeException ("count");
+
+      return count > 0
+             ? urlDecodeToBytes (bytes, offset, count)
+             : new byte[0];
+    }
+
+    public static string UrlEncode (byte[] bytes)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      return len > 0
+             ? Encoding.ASCII.GetString (urlEncodeToBytes (bytes, 0, len))
+             : String.Empty;
+    }
+
+    public static string UrlEncode (string s)
+    {
+      return UrlEncode (s, Encoding.UTF8);
+    }
+
+    public static string UrlEncode (string s, Encoding encoding)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      var len = s.Length;
+      if (len == 0)
+        return s;
+
+      if (encoding == null)
+        encoding = Encoding.UTF8;
+
+      var bytes = new byte[encoding.GetMaxByteCount (len)];
+      var realLen = encoding.GetBytes (s, 0, len, bytes, 0);
+
+      return Encoding.ASCII.GetString (urlEncodeToBytes (bytes, 0, realLen));
+    }
+
+    public static string UrlEncode (byte[] bytes, int offset, int count)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      if (len == 0) {
+        if (offset != 0)
+          throw new ArgumentOutOfRangeException ("offset");
+
+        if (count != 0)
+          throw new ArgumentOutOfRangeException ("count");
+
+        return String.Empty;
+      }
+
+      if (offset < 0 || offset >= len)
+        throw new ArgumentOutOfRangeException ("offset");
+
+      if (count < 0 || count > len - offset)
+        throw new ArgumentOutOfRangeException ("count");
+
+      return count > 0
+             ? Encoding.ASCII.GetString (
+                 urlEncodeToBytes (bytes, offset, count)
+               )
+             : String.Empty;
+    }
+
+    public static byte[] UrlEncodeToBytes (byte[] bytes)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      return len > 0 ? urlEncodeToBytes (bytes, 0, len) : bytes;
+    }
+
+    public static byte[] UrlEncodeToBytes (string s)
+    {
+      return UrlEncodeToBytes (s, Encoding.UTF8);
+    }
+
+    public static byte[] UrlEncodeToBytes (string s, Encoding encoding)
+    {
+      if (s == null)
+        throw new ArgumentNullException ("s");
+
+      if (s.Length == 0)
+        return new byte[0];
+
+      var bytes = (encoding ?? Encoding.UTF8).GetBytes (s);
+      return urlEncodeToBytes (bytes, 0, bytes.Length);
+    }
+
+    public static byte[] UrlEncodeToBytes (byte[] bytes, int offset, int count)
+    {
+      if (bytes == null)
+        throw new ArgumentNullException ("bytes");
+
+      var len = bytes.Length;
+      if (len == 0) {
+        if (offset != 0)
+          throw new ArgumentOutOfRangeException ("offset");
+
+        if (count != 0)
+          throw new ArgumentOutOfRangeException ("count");
+
+        return bytes;
+      }
+
+      if (offset < 0 || offset >= len)
+        throw new ArgumentOutOfRangeException ("offset");
+
+      if (count < 0 || count > len - offset)
+        throw new ArgumentOutOfRangeException ("count");
+
+      return count > 0 ? urlEncodeToBytes (bytes, offset, count) : new byte[0];
+    }
+
+    #endregion
+  }
+}

+ 73 - 0
src/websocket-sharp/Net/HttpVersion.cs

@@ -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 <[email protected]>
+ */
+#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
+  }
+}

+ 52 - 0
src/websocket-sharp/Net/InputChunkState.cs

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

+ 49 - 0
src/websocket-sharp/Net/InputState.cs

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

+ 50 - 0
src/websocket-sharp/Net/LineState.cs

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

+ 209 - 0
src/websocket-sharp/Net/NetworkCredential.cs

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

+ 150 - 0
src/websocket-sharp/Net/QueryStringCollection.cs

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

+ 124 - 0
src/websocket-sharp/Net/ReadBufferState.cs

@@ -0,0 +1,124 @@
+#region License
+/*
+ * ReadBufferState.cs
+ *
+ * This code is derived from ChunkedInputStream.cs (System.Net) of Mono
+ * (http://www.mono-project.com).
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+ * Copyright (c) 2014-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 <[email protected]>
+ */
+#endregion
+
+using System;
+
+namespace WebSocketSharp.Net
+{
+  internal class ReadBufferState
+  {
+    #region Private Fields
+
+    private HttpStreamAsyncResult _asyncResult;
+    private byte[]                _buffer;
+    private int                   _count;
+    private int                   _initialCount;
+    private int                   _offset;
+
+    #endregion
+
+    #region Public Constructors
+
+    public ReadBufferState (
+      byte[] buffer, int offset, int count, HttpStreamAsyncResult asyncResult)
+    {
+      _buffer = buffer;
+      _offset = offset;
+      _count = count;
+      _initialCount = count;
+      _asyncResult = asyncResult;
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    public HttpStreamAsyncResult AsyncResult {
+      get {
+        return _asyncResult;
+      }
+
+      set {
+        _asyncResult = value;
+      }
+    }
+
+    public byte[] Buffer {
+      get {
+        return _buffer;
+      }
+
+      set {
+        _buffer = value;
+      }
+    }
+
+    public int Count {
+      get {
+        return _count;
+      }
+
+      set {
+        _count = value;
+      }
+    }
+
+    public int InitialCount {
+      get {
+        return _initialCount;
+      }
+
+      set {
+        _initialCount = value;
+      }
+    }
+
+    public int Offset {
+      get {
+        return _offset;
+      }
+
+      set {
+        _offset = value;
+      }
+    }
+
+    #endregion
+  }
+}

+ 267 - 0
src/websocket-sharp/Net/RequestStream.cs

@@ -0,0 +1,267 @@
+#region License
+/*
+ * RequestStream.cs
+ *
+ * This code is derived from RequestStream.cs (System.Net) of Mono
+ * (http://www.mono-project.com).
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+ * Copyright (c) 2012-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 <[email protected]>
+ */
+#endregion
+
+using System;
+using System.IO;
+
+namespace WebSocketSharp.Net
+{
+  internal class RequestStream : Stream
+  {
+    #region Private Fields
+
+    private long    _bodyLeft;
+    private byte[]  _buffer;
+    private int     _count;
+    private bool    _disposed;
+    private int     _offset;
+    private Stream  _stream;
+
+    #endregion
+
+    #region Internal Constructors
+
+    internal RequestStream (Stream stream, byte[] buffer, int offset, int count)
+      : this (stream, buffer, offset, count, -1)
+    {
+    }
+
+    internal RequestStream (
+      Stream stream, byte[] buffer, int offset, int count, long contentLength)
+    {
+      _stream = stream;
+      _buffer = buffer;
+      _offset = offset;
+      _count = count;
+      _bodyLeft = contentLength;
+    }
+
+    #endregion
+
+    #region Public Properties
+
+    public override bool CanRead {
+      get {
+        return true;
+      }
+    }
+
+    public override bool CanSeek {
+      get {
+        return false;
+      }
+    }
+
+    public override bool CanWrite {
+      get {
+        return false;
+      }
+    }
+
+    public override long Length {
+      get {
+        throw new NotSupportedException ();
+      }
+    }
+
+    public override long Position {
+      get {
+        throw new NotSupportedException ();
+      }
+
+      set {
+        throw new NotSupportedException ();
+      }
+    }
+
+    #endregion
+
+    #region Private Methods
+
+    // Returns 0 if we can keep reading from the base stream,
+    // > 0 if we read something from the buffer,
+    // -1 if we had a content length set and we finished reading that many bytes.
+    private int fillFromBuffer (byte[] buffer, int offset, int count)
+    {
+      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.");
+
+      if (_bodyLeft == 0)
+        return -1;
+
+      if (_count == 0 || count == 0)
+        return 0;
+
+      if (count > _count)
+        count = _count;
+
+      if (_bodyLeft > 0 && count > _bodyLeft)
+        count = (int) _bodyLeft;
+
+      Buffer.BlockCopy (_buffer, _offset, buffer, offset, count);
+      _offset += count;
+      _count -= count;
+      if (_bodyLeft > 0)
+        _bodyLeft -= count;
+
+      return count;
+    }
+
+    #endregion
+
+    #region Public Methods
+
+    public override IAsyncResult BeginRead (
+      byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+    {
+      if (_disposed)
+        throw new ObjectDisposedException (GetType ().ToString ());
+
+      var nread = fillFromBuffer (buffer, offset, count);
+      if (nread > 0 || nread == -1) {
+        var ares = new HttpStreamAsyncResult (callback, state);
+        ares.Buffer = buffer;
+        ares.Offset = offset;
+        ares.Count = count;
+        ares.SyncRead = nread > 0 ? nread : 0;
+        ares.Complete ();
+
+        return ares;
+      }
+
+      // Avoid reading past the end of the request to allow for HTTP pipelining.
+      if (_bodyLeft >= 0 && count > _bodyLeft)
+        count = (int) _bodyLeft;
+
+      return _stream.BeginRead (buffer, offset, count, callback, state);
+    }
+
+    public override IAsyncResult BeginWrite (
+      byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+    {
+      throw new NotSupportedException ();
+    }
+
+    public override void Close ()
+    {
+      _disposed = true;
+    }
+
+    public override int EndRead (IAsyncResult asyncResult)
+    {
+      if (_disposed)
+        throw new ObjectDisposedException (GetType ().ToString ());
+
+      if (asyncResult == null)
+        throw new ArgumentNullException ("asyncResult");
+
+      if (asyncResult is HttpStreamAsyncResult) {
+        var ares = (HttpStreamAsyncResult) asyncResult;
+        if (!ares.IsCompleted)
+          ares.AsyncWaitHandle.WaitOne ();
+
+        return ares.SyncRead;
+      }
+
+      // Close on exception?
+      var nread = _stream.EndRead (asyncResult);
+      if (nread > 0 && _bodyLeft > 0)
+        _bodyLeft -= nread;
+
+      return nread;
+    }
+
+    public override void EndWrite (IAsyncResult asyncResult)
+    {
+      throw new NotSupportedException ();
+    }
+
+    public override void Flush ()
+    {
+    }
+
+    public override int Read (byte[] buffer, int offset, int count)
+    {
+      if (_disposed)
+        throw new ObjectDisposedException (GetType ().ToString ());
+
+      // Call the fillFromBuffer method to check for buffer boundaries even when _bodyLeft is 0.
+      var nread = fillFromBuffer (buffer, offset, count);
+      if (nread == -1) // No more bytes available (Content-Length).
+        return 0;
+
+      if (nread > 0)
+        return nread;
+
+      nread = _stream.Read (buffer, offset, count);
+      if (nread > 0 && _bodyLeft > 0)
+        _bodyLeft -= nread;
+
+      return nread;
+    }
+
+    public override long Seek (long offset, SeekOrigin origin)
+    {
+      throw new NotSupportedException ();
+    }
+
+    public override void SetLength (long value)
+    {
+      throw new NotSupportedException ();
+    }
+
+    public override void Write (byte[] buffer, int offset, int count)
+    {
+      throw new NotSupportedException ();
+    }
+
+    #endregion
+  }
+}

+ 403 - 0
src/websocket-sharp/Net/ResponseStream.cs

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

+ 236 - 0
src/websocket-sharp/Net/ServerSslConfiguration.cs

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

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません