fix Ext.cs, WebSocket.cs for implementation of Sec-WebSocket-Key*.
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
@@ -40,11 +41,91 @@ namespace WebSocketSharp
|
||||
return b == Convert.ToByte(c);
|
||||
}
|
||||
|
||||
public static void NotEqualsDo(this string a, string b, Action<string> action)
|
||||
public static uint GenerateKey(this Random rand, int space)
|
||||
{
|
||||
uint max = (uint)(0xffffffff / space);
|
||||
|
||||
int upper16 = (int)((max & 0xffff0000) >> 16);
|
||||
int lower16 = (int)(max & 0x0000ffff);
|
||||
|
||||
return ((uint)rand.Next(upper16 + 1) << 16) + (uint)rand.Next(lower16 + 1);
|
||||
}
|
||||
|
||||
public static string GenerateSecKey(this Random rand, out uint key)
|
||||
{
|
||||
int space = rand.Next(1, 13);
|
||||
int ascii = rand.Next(1, 13);
|
||||
|
||||
key = rand.GenerateKey(space);
|
||||
|
||||
long mKey = key * space;
|
||||
char[] mKeyChars = mKey.ToString().ToCharArray();
|
||||
int mKeyCharsLen = mKeyChars.Length;
|
||||
|
||||
int secKeyCharsLen = mKeyCharsLen + space + ascii;
|
||||
char[] secKeyChars = new char[secKeyCharsLen].InitializeWith(' ');
|
||||
|
||||
secKeyChars[0] = mKeyChars[0];
|
||||
secKeyChars[secKeyCharsLen - 1] = mKeyChars[mKeyCharsLen - 1];
|
||||
|
||||
int i = 0;
|
||||
for (int j = 1; j < mKeyCharsLen - 1; j++)
|
||||
{
|
||||
i = rand.Next(i + 1, secKeyCharsLen - mKeyCharsLen + j + 1);
|
||||
secKeyChars[i] = mKeyChars[j];
|
||||
}
|
||||
|
||||
var convToAscii = secKeyChars
|
||||
.IndexOf(' ')
|
||||
.OrderBy( x => Guid.NewGuid() )
|
||||
.Where( (x, idx) => idx < ascii );
|
||||
|
||||
int k;
|
||||
foreach (int index in convToAscii)
|
||||
{
|
||||
k = rand.Next(2) == 0 ? rand.Next(33, 48) : rand.Next(58, 127);
|
||||
secKeyChars[index] = Convert.ToChar(k);
|
||||
}
|
||||
|
||||
return new String(secKeyChars);
|
||||
}
|
||||
|
||||
public static IEnumerable<int> IndexOf<T>(this T[] array, T val)
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
if (array[i].Equals(val))
|
||||
{
|
||||
yield return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static T[] InitializeWith<T>(this T[] array, T val)
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = val;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static Byte[] InitializeWithASCII(this Byte[] bytes, Random rand)
|
||||
{
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
bytes[i] = (byte)rand.Next(32, 127);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static void NotEqualsDo(this string a, string b, Action<string, string> action)
|
||||
{
|
||||
if (a != b)
|
||||
{
|
||||
action(a);
|
||||
action(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -33,11 +33,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
@@ -256,17 +258,39 @@ namespace WebSocketSharp
|
||||
host += ":" + port;
|
||||
}
|
||||
|
||||
string subprotocol = protocol != String.Empty
|
||||
string subProtocol = protocol != String.Empty
|
||||
? String.Format("Sec-WebSocket-Protocol: {0}\r\n", protocol)
|
||||
: protocol;
|
||||
#if !CHALLENGE
|
||||
string secKeys = String.Empty;
|
||||
string key3AsASCII = String.Empty;
|
||||
#else
|
||||
Random rand = new Random();
|
||||
|
||||
uint key1, key2;
|
||||
string secKey1 = rand.GenerateSecKey(out key1);
|
||||
string secKey2 = rand.GenerateSecKey(out key2);
|
||||
|
||||
byte[] key3 = new byte[8].InitializeWithASCII(rand);
|
||||
|
||||
string secKeys = "Sec-WebSocket-Key1: {0}\r\n" +
|
||||
"Sec-WebSocket-Key2: {1}\r\n";
|
||||
secKeys = String.Format(secKeys, secKey1, secKey2);
|
||||
|
||||
string key3AsASCII = Encoding.ASCII.GetString(key3);
|
||||
|
||||
byte[] expectedRes = createExpectedRes(key1, key2, key3);
|
||||
byte[] actualRes = new byte[16];
|
||||
#endif
|
||||
string request = "GET " + path + " HTTP/1.1\r\n" +
|
||||
"Upgrade: WebSocket\r\n" +
|
||||
"Connection: Upgrade\r\n" +
|
||||
subprotocol +
|
||||
subProtocol +
|
||||
"Host: " + host + "\r\n" +
|
||||
"Origin: " + origin + "\r\n" +
|
||||
"\r\n";
|
||||
secKeys +
|
||||
"\r\n" +
|
||||
key3AsASCII;
|
||||
#if DEBUG
|
||||
Console.WriteLine("WS: Info @doHandshake: Handshake from client: \n{0}", request);
|
||||
#endif
|
||||
@@ -283,6 +307,10 @@ namespace WebSocketSharp
|
||||
wsStream.ReadByte().EqualsWithSaveTo('\r', rawdata) &&
|
||||
wsStream.ReadByte().EqualsWithSaveTo('\n', rawdata))
|
||||
{
|
||||
#if CHALLENGE
|
||||
wsStream.Read(actualRes, 0, actualRes.Length);
|
||||
rawdata.AddRange(actualRes);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -297,15 +325,25 @@ namespace WebSocketSharp
|
||||
Console.WriteLine("{0}", s);
|
||||
}
|
||||
#endif
|
||||
Action<string> action = s => { throw new IOException("Invalid handshake response: " + s); };
|
||||
Action<string, string> action = (a, b) =>
|
||||
{
|
||||
throw new IOException("Invalid handshake response: " + a);
|
||||
};
|
||||
#if !CHALLENGE
|
||||
response[0].NotEqualsDo("HTTP/1.1 101 Web Socket Protocol Handshake", action);
|
||||
#else
|
||||
response[0].NotEqualsDo("HTTP/1.1 101 WebSocket Protocol Handshake", action);
|
||||
#endif
|
||||
response[1].NotEqualsDo("Upgrade: WebSocket", action);
|
||||
response[2].NotEqualsDo("Connection: Upgrade", action);
|
||||
|
||||
for (int i = 3; i < response.Length; i++)
|
||||
{
|
||||
#if !CHALLENGE
|
||||
if (response[i].Contains("WebSocket-Protocol:"))
|
||||
// if (response[i].Contains("Sec-WebSocket-Protocol:"))
|
||||
#else
|
||||
if (response[i].Contains("Sec-WebSocket-Protocol:"))
|
||||
#endif
|
||||
{
|
||||
int j = response[i].IndexOf(":");
|
||||
protocol = response[i].Substring(j + 1).Trim();
|
||||
@@ -315,10 +353,39 @@ namespace WebSocketSharp
|
||||
#if DEBUG
|
||||
Console.WriteLine("WS: Info @doHandshake: Sub protocol: {0}", protocol);
|
||||
#endif
|
||||
#if CHALLENGE
|
||||
string expectedResHexStr = BitConverter.ToString(expectedRes);
|
||||
string actualResHexStr = BitConverter.ToString(actualRes);
|
||||
|
||||
actualResHexStr.NotEqualsDo(expectedResHexStr, (a, b) =>
|
||||
{
|
||||
Console.WriteLine("WS: Error @doHandshake: Invalid challenge response.");
|
||||
Console.WriteLine("\texpected: {0}", b);
|
||||
Console.WriteLine("\tactual : {0}", a);
|
||||
throw new IOException("Invalid challenge response: " + a);
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Console.WriteLine("WS: Info @doHandshake: challenge response: {0}", actualResHexStr);
|
||||
#endif
|
||||
#endif
|
||||
ReadyState = WsState.OPEN;
|
||||
}
|
||||
|
||||
private byte[] createExpectedRes(uint key1, uint key2, byte[] key3)
|
||||
{
|
||||
byte[] key1Bytes = BitConverter.GetBytes(key1);
|
||||
byte[] key2Bytes = BitConverter.GetBytes(key2);
|
||||
|
||||
Array.Reverse(key1Bytes);
|
||||
Array.Reverse(key2Bytes);
|
||||
|
||||
byte[] concatKeys = key1Bytes.Concat(key2Bytes).Concat(key3).ToArray();
|
||||
|
||||
MD5 md5 = MD5.Create();
|
||||
return md5.ComputeHash(concatKeys);
|
||||
}
|
||||
|
||||
private void message()
|
||||
{
|
||||
#if DEBUG
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -16,7 +16,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<DefineConstants>DEBUG,CHALLENGE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
@@ -34,7 +34,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug_Ubuntu</OutputPath>
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<DefineConstants>DEBUG,CHALLENGE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
|
Binary file not shown.
Reference in New Issue
Block a user