Fix due to the added ResponseHandshake.cs

This commit is contained in:
sta
2012-08-31 17:41:15 +09:00
parent 7ea798e321
commit 75417fba70
50 changed files with 238 additions and 172 deletions

View File

@@ -0,0 +1,81 @@
#region MIT License
/**
* Handshake.cs
*
* The MIT License
*
* Copyright (c) 2012 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 {
public abstract class Handshake {
protected const string _crlf = "\r\n";
protected Handshake()
{
}
public NameValueCollection Headers { get; protected set; }
public string Version { get; protected set; }
public void AddHeader(string name, string value)
{
Headers.Add(name, value);
}
public string[] GetHeaderValues(string name)
{
return Headers.GetValues(name);
}
public bool HeaderExists(string name)
{
return Headers[name] != null
? true
: false;
}
public bool HeaderExists(string name, string value)
{
var values = GetHeaderValues(name);
if (values == null)
return false;
foreach (string v in values)
if (String.Compare(value, v, true) == 0)
return true;
return false;
}
public byte[] ToBytes()
{
return Encoding.UTF8.GetBytes(ToString());
}
}
}

View File

@@ -28,16 +28,13 @@
using System;
using System.Net;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
namespace WebSocketSharp
{
public class RequestHandshake
{
private const string _crlf = "\r\n";
namespace WebSocketSharp {
public class RequestHandshake : Handshake
{
private RequestHandshake()
{
}
@@ -53,8 +50,6 @@ namespace WebSocketSharp
AddHeader("Connection", "Upgrade");
}
public NameValueCollection Headers { get; private set; }
public bool IsWebSocketRequest {
get {
@@ -85,26 +80,14 @@ namespace WebSocketSharp
public string Method { get; private set; }
public string Uri { get; private set; }
public string Version { get; private set; }
public static RequestHandshake Parse(byte[] data)
{
var request = Encoding.UTF8.GetString(data)
.Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
.Split('\n');
return Parse(request);
}
public static RequestHandshake Parse(string[] request)
{
var requestLine = request[0].Split(' ');
if (requestLine.Length != 3)
throw new ArgumentException("Invalid request line.");
var headers = new WebHeaderCollection();
for (int i = 1; i < request.Length; i++)
headers.Add(request[i]);
@@ -116,42 +99,6 @@ namespace WebSocketSharp
};
}
public void AddHeader(string name, string value)
{
Headers.Add(name, value);
}
public string[] GetHeaderValues(string name)
{
return Headers.GetValues(name);
}
public bool HeaderExists(string name)
{
return Headers[name] != null
? true
: false;
}
public bool HeaderExists(string name, string value)
{
var values = GetHeaderValues(name);
if (values == null)
return false;
foreach (string v in values)
if (String.Compare(value, v, true) == 0)
return true;
return false;
}
public byte[] ToBytes()
{
return Encoding.UTF8.GetBytes(ToString());
}
public override string ToString()
{
var buffer = new StringBuilder();

View File

@@ -0,0 +1,110 @@
#region MIT License
/**
* ResponseHandshake.cs
*
* The MIT License
*
* Copyright (c) 2012 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.Net;
using System.Text;
namespace WebSocketSharp {
public class ResponseHandshake : Handshake
{
public ResponseHandshake()
{
Version = "HTTP/1.1";
Status = "101";
Reason = "Switching Protocols";
Headers = new NameValueCollection();
AddHeader("Upgrade", "websocket");
AddHeader("Connection", "Upgrade");
}
public bool IsWebSocketResponse {
get {
if (Version != "HTTP/1.1")
return false;
if (Status != "101")
return false;
if (!HeaderExists("Upgrade", "websocket"))
return false;
if (!HeaderExists("Connection", "Upgrade"))
return false;
if (!HeaderExists("Sec-WebSocket-Accept"))
return false;
return true;
}
}
public string Reason { get; private set; }
public string Status { get; private set; }
public static ResponseHandshake Parse(string[] response)
{
var statusLine = response[0].Split(' ');
if (statusLine.Length < 3)
throw new ArgumentException("Invalid status line.");
var reason = new StringBuilder(statusLine[2]);
for (int i = 3; i < statusLine.Length; i++)
reason.AppendFormat(" {0}", statusLine[i]);
var headers = new WebHeaderCollection();
for (int i = 1; i < response.Length; i++)
headers.Add(response[i]);
return new ResponseHandshake {
Headers = headers,
Reason = reason.ToString(),
Status = statusLine[1],
Version = statusLine[0]
};
}
public override string ToString()
{
var buffer = new StringBuilder();
buffer.AppendFormat("{0} {1} {2}{3}", Version, Status, Reason, _crlf);
foreach (string key in Headers.AllKeys)
buffer.AppendFormat("{0}: {1}{2}", key, Headers[key], _crlf);
buffer.Append(_crlf);
return buffer.ToString();
}
}
}

View File

@@ -251,7 +251,7 @@ namespace WebSocketSharp
var response = createResponseHandshake();
#if DEBUG
Console.WriteLine("WS: Info@acceptHandshake: Opening handshake from server:\n");
Console.WriteLine(response);
Console.WriteLine(response.ToString());
#endif
sendResponseHandshake(response);
@@ -435,24 +435,12 @@ namespace WebSocketSharp
return request;
}
private string createResponseHandshake()
private ResponseHandshake createResponseHandshake()
{
string crlf = "\r\n";
var response = new ResponseHandshake();
response.AddHeader("Sec-WebSocket-Accept", createExpectedKey());
string resStatus = "HTTP/1.1 101 Switching Protocols" + crlf;
string resUpgrade = "Upgrade: websocket" + crlf;
string resConnection = "Connection: Upgrade" + crlf;
string secWsAccept = String.Format("Sec-WebSocket-Accept: {0}{1}", createExpectedKey(), crlf);
//string secWsProtocol = "Sec-WebSocket-Protocol: chat" + crlf;
string secWsVersion = String.Format("Sec-WebSocket-Version: {0}{1}", _version, crlf);
return resStatus +
resUpgrade +
resConnection +
secWsAccept +
//secWsProtocol +
secWsVersion +
crlf;
return response;
}
private void createServerStream()
@@ -467,32 +455,28 @@ namespace WebSocketSharp
_sslStream.AuthenticateAsServer(new X509Certificate(certPath));
_wsStream = new WsStream<SslStream>(_sslStream);
return;
}
else
{
_wsStream = new WsStream<NetworkStream>(_netStream);
}
_wsStream = new WsStream<NetworkStream>(_netStream);
}
private void doHandshake()
{
var request = createOpeningHandshake();
#if DEBUG
Console.WriteLine("WS: Info@doHandshake: Opening handshake from client:\n{0}", request);
Console.WriteLine("WS: Info@doHandshake: Opening handshake from client:\n");
Console.WriteLine(request.ToString());
#endif
var response = sendOpeningHandshake(request);
#if DEBUG
Console.WriteLine("WS: Info@doHandshake: Opening handshake from server:\n");
foreach (string s in response)
{
Console.WriteLine("{0}", s);
}
Console.WriteLine(response.ToString());
#endif
string msg;
if (!isValidResponse(response, out msg))
{
throw new InvalidOperationException(msg);
}
ReadyState = WsState.OPEN;
}
@@ -552,87 +536,35 @@ namespace WebSocketSharp
return true;
}
private bool isValidResponse(string[] response, out string message)
private bool isValidResponse(ResponseHandshake response, out string message)
{
string resUpgrade, resConnection, secWsAccept, secWsVersion;
string[] resStatus;
List<string> extensionList = new List<string>();
Func<string, Func<string, string, string>> func = s =>
{
return (e, a) =>
{
return String.Format("Invalid response {0} value: {1}(expected: {2})", s, a, e);
};
};
resStatus = response[0].Split(' ');
if ("HTTP/1.1".NotEqualsDo(resStatus[0], func("HTTP Version"), out message, false))
{
return false;
}
if ("101".NotEqualsDo(resStatus[1], func("Status Code"), out message, false))
if (!response.IsWebSocketResponse)
{
message = "Not WebSocket response.";
return false;
}
for (int i = 1; i < response.Length; i++)
if (!response.HeaderExists("Sec-WebSocket-Accept", createExpectedKey()))
{
if (response[i].Contains("Upgrade:"))
message = "Invalid Sec-WebSocket-Accept value.";
return false;
}
if (response.HeaderExists("Sec-WebSocket-Version"))
{
if (!response.HeaderExists("Sec-WebSocket-Version", _version))
{
resUpgrade = response[i].GetHeaderValue(":");
if ("websocket".NotEqualsDo(resUpgrade, func("Upgrade"), out message, true))
{
return false;
}
}
else if (response[i].Contains("Connection:"))
{
resConnection = response[i].GetHeaderValue(":");
if ("Upgrade".NotEqualsDo(resConnection, func("Connection"), out message, true))
{
return false;
}
}
else if (response[i].Contains("Sec-WebSocket-Accept:"))
{
secWsAccept = response[i].GetHeaderValue(":");
if (createExpectedKey().NotEqualsDo(secWsAccept, func("Sec-WebSocket-Accept"), out message, false))
{
return false;
}
}
else if (response[i].Contains("Sec-WebSocket-Extensions:"))
{
extensionList.Add(response[i].GetHeaderValue(":"));
}
else if (response[i].Contains("Sec-WebSocket-Protocol:"))
{
_protocol = response[i].GetHeaderValue(":");
#if DEBUG
Console.WriteLine("WS: Info@isValidResponse: Sub protocol: {0}", _protocol);
#endif
}
else if (response[i].Contains("Sec-WebSocket-Version:"))
{
secWsVersion = response[i].GetHeaderValue(":");
if (_version.NotEqualsDo(secWsVersion, func("Sec-WebSocket-Version"), out message, true))
{
return false;
}
}
else
{
Console.WriteLine("WS: Info@isValidResponse: Unsupported response header line: {0}", response[i]);
message = "Unsupported Sec-WebSocket-Version.";
return false;
}
}
#if DEBUG
foreach (string s in extensionList)
{
Console.WriteLine("WS: Info@isValidResponse: Extensions: {0}", s);
}
#endif
if (response.HeaderExists("Sec-WebSocket-Protocol"))
_protocol = response.Headers["Sec-WebSocket-Protocol"];
if (response.HeaderExists("Sec-WebSocket-Extensions"))
_extensions = response.Headers["Sec-WebSocket-Extensions"];
message = String.Empty;
return true;
}
@@ -641,9 +573,7 @@ namespace WebSocketSharp
{
string scheme = uri.Scheme;
if (scheme == "ws" || scheme == "wss")
{
return true;
}
return false;
}
@@ -704,7 +634,7 @@ namespace WebSocketSharp
pong(payloadData);
}
private byte[] readHandshake()
private string[] readHandshake()
{
var buffer = new List<byte>();
@@ -717,7 +647,9 @@ namespace WebSocketSharp
break;
}
return buffer.ToArray();
return Encoding.UTF8.GetString(buffer.ToArray())
.Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
.Split('\n');
}
private MessageEventArgs receive()
@@ -980,21 +912,15 @@ namespace WebSocketSharp
return readLen;
}
private string[] sendOpeningHandshake(RequestHandshake request)
private ResponseHandshake sendOpeningHandshake(RequestHandshake request)
{
_wsStream.Write(request.ToBytes(), 0, request.ToBytes().Length);
var readData = readHandshake();
return Encoding.UTF8.GetString(readData)
.Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
.Split('\n');
return ResponseHandshake.Parse(readHandshake());
}
private void sendResponseHandshake(string value)
private void sendResponseHandshake(ResponseHandshake response)
{
var buffer = Encoding.UTF8.GetBytes(value);
_wsStream.Write(buffer, 0, buffer.Length);
_wsStream.Write(response.ToBytes(), 0, response.ToBytes().Length);
}
private void startMessageThread()

View File

@@ -77,6 +77,8 @@
<Compile Include="IWsStream.cs" />
<Compile Include="WsStream.cs" />
<Compile Include="RequestHandshake.cs" />
<Compile Include="ResponseHandshake.cs" />
<Compile Include="Handshake.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

Binary file not shown.