Modified connecting

This commit is contained in:
sta 2014-01-06 16:57:36 +09:00
parent 809e5ab58c
commit 0407486041

View File

@ -69,7 +69,7 @@ namespace WebSocketSharp
#region Private Fields #region Private Fields
private AuthenticationChallenge _authChallenge; private AuthenticationChallenge _authChallenge;
private string _base64key; private string _base64Key;
private RemoteCertificateValidationCallback private RemoteCertificateValidationCallback
_certValidationCallback; _certValidationCallback;
private bool _client; private bool _client;
@ -168,7 +168,7 @@ namespace WebSocketSharp
_protocols = protocols.ToString (", "); _protocols = protocols.ToString (", ");
_base64key = createBase64Key (); _base64Key = CreateBase64Key ();
_client = true; _client = true;
_logger = new Logger (); _logger = new Logger ();
_secure = _uri.Scheme == "wss"; _secure = _uri.Scheme == "wss";
@ -487,22 +487,26 @@ namespace WebSocketSharp
// As server // As server
private bool acceptHandshake () private bool acceptHandshake ()
{ {
_logger.Debug (String.Format ( _logger.Debug (
"A WebSocket connection request from {0}:\n{1}", _context.UserEndPoint, _context)); String.Format (
"A WebSocket connection request from {0}:\n{1}",
_context.UserEndPoint,
_context));
if (!validateConnectionRequest (_context)) var err = checkIfValidHandshakeRequest (_context);
{ if (err != null) {
_logger.Error ("An invalid WebSocket connection request."); _logger.Error (err);
error ("An error has occurred while handshaking."); error ("An error has occurred while connecting.");
Close (HttpStatusCode.BadRequest); Close (HttpStatusCode.BadRequest);
return false; return false;
} }
_base64key = _context.SecWebSocketKey; _base64Key = _context.SecWebSocketKey;
if (_protocol.Length > 0 && !_context.Headers.Contains ("Sec-WebSocket-Protocol", _protocol)) if (_protocol.Length > 0 &&
!_context.Headers.Contains ("Sec-WebSocket-Protocol", _protocol))
_protocol = String.Empty; _protocol = String.Empty;
var extensions = _context.Headers ["Sec-WebSocket-Extensions"]; var extensions = _context.Headers ["Sec-WebSocket-Extensions"];
@ -512,6 +516,45 @@ namespace WebSocketSharp
return send (createHandshakeResponse ()); return send (createHandshakeResponse ());
} }
// As server
private string checkIfValidHandshakeRequest (WebSocketContext context)
{
string key, version;
return !context.IsWebSocketRequest
? "Not WebSocket connection request."
: !validateHostHeader (context.Host)
? "Invalid Host header."
: (key = context.SecWebSocketKey) == null || key.Length == 0
? "Invalid Sec-WebSocket-Key header."
: (version = context.SecWebSocketVersion) == null ||
version != _version
? "Invalid Sec-WebSocket-Version header."
: !validateCookies (context.CookieCollection, _cookies)
? "Invalid Cookies."
: null;
}
// As client
private string checkIfValidHandshakeResponse (HandshakeResponse response)
{
var headers = response.Headers;
string accept, version;
return response.IsUnauthorized
? String.Format (
"An HTTP {0} authorization is required.",
response.AuthChallenge.Scheme)
: !response.IsWebSocketResponse
? "Not WebSocket connection response to the connection request."
: (accept = headers ["Sec-WebSocket-Accept"]) == null ||
accept != CreateResponseKey (_base64Key)
? "Invalid Sec-WebSocket-Accept header."
: (version = headers ["Sec-WebSocket-Version"]) != null &&
version != _version
? "Invalid Sec-WebSocket-Version header."
: null;
}
private void close (CloseStatusCode code, string reason, bool wait) private void close (CloseStatusCode code, string reason, bool wait)
{ {
close (new PayloadData (((ushort) code).Append (reason)), !code.IsReserved (), wait); close (new PayloadData (((ushort) code).Append (reason)), !code.IsReserved (), wait);
@ -649,7 +692,7 @@ namespace WebSocketSharp
return true; return true;
} }
private void connect () private bool connect ()
{ {
lock (_forConnect) { lock (_forConnect) {
if (IsOpened) { if (IsOpened) {
@ -657,30 +700,24 @@ namespace WebSocketSharp
_logger.Error (msg); _logger.Error (msg);
error (msg); error (msg);
return; return false;
} }
try { try {
if (_client ? doHandshake () : acceptHandshake ()) if (_client ? doHandshake () : acceptHandshake ()) {
open (); _readyState = WebSocketState.OPEN;
return true;
}
} }
catch (Exception ex) { catch (Exception ex) {
processException ( processException (
ex, "An exception has occurred while connecting or opening."); ex, "An exception has occurred while connecting.");
} }
return false;
} }
} }
// As client
private static string createBase64Key ()
{
var src = new byte [16];
var rand = new Random ();
rand.NextBytes (src);
return Convert.ToBase64String (src);
}
// As client // As client
private string createExtensionsRequest () private string createExtensionsRequest ()
{ {
@ -709,7 +746,7 @@ namespace WebSocketSharp
if (!_origin.IsNullOrEmpty ()) if (!_origin.IsNullOrEmpty ())
headers ["Origin"] = _origin; headers ["Origin"] = _origin;
headers ["Sec-WebSocket-Key"] = _base64key; headers ["Sec-WebSocket-Key"] = _base64Key;
if (!_protocols.IsNullOrEmpty ()) if (!_protocols.IsNullOrEmpty ())
headers ["Sec-WebSocket-Protocol"] = _protocols; headers ["Sec-WebSocket-Protocol"] = _protocols;
@ -744,7 +781,7 @@ namespace WebSocketSharp
var res = new HandshakeResponse (HttpStatusCode.SwitchingProtocols); var res = new HandshakeResponse (HttpStatusCode.SwitchingProtocols);
var headers = res.Headers; var headers = res.Headers;
headers ["Sec-WebSocket-Accept"] = createResponseKey (); headers ["Sec-WebSocket-Accept"] = CreateResponseKey (_base64Key);
if (_protocol.Length > 0) if (_protocol.Length > 0)
headers ["Sec-WebSocket-Protocol"] = _protocol; headers ["Sec-WebSocket-Protocol"] = _protocol;
@ -767,32 +804,16 @@ namespace WebSocketSharp
return res; return res;
} }
private string createResponseKey ()
{
var buffer = new StringBuilder (_base64key, 64);
buffer.Append (_guid);
SHA1 sha1 = new SHA1CryptoServiceProvider ();
var src = sha1.ComputeHash (Encoding.UTF8.GetBytes (buffer.ToString ()));
return Convert.ToBase64String (src);
}
// As client // As client
private bool doHandshake () private bool doHandshake ()
{ {
setClientStream (); setClientStream ();
var res = sendHandshakeRequest (); var res = sendHandshakeRequest ();
var err = res.IsUnauthorized var err = checkIfValidHandshakeResponse (res);
? String.Format ("An HTTP {0} authorization is required.", res.AuthChallenge.Scheme) if (err != null) {
: !validateConnectionResponse (res)
? "An invalid response to this WebSocket connection request."
: null;
if (err != null)
{
_logger.Error (err); _logger.Error (err);
var msg = "An error has occurred while handshaking."; var msg = "An error has occurred while connecting.";
error (msg); error (msg);
close (CloseStatusCode.ABNORMAL, msg, false); close (CloseStatusCode.ABNORMAL, msg, false);
@ -831,10 +852,14 @@ namespace WebSocketSharp
private void open () private void open ()
{ {
_readyState = WebSocketState.OPEN; try {
OnOpen.Emit (this, EventArgs.Empty);
OnOpen.Emit (this, EventArgs.Empty); startReceiving ();
startReceiving (); }
catch (Exception ex) {
processException (
ex, "An exception has occurred while opening.");
}
} }
private bool processCloseFrame (WsFrame frame) private bool processCloseFrame (WsFrame frame)
@ -1270,13 +1295,15 @@ namespace WebSocketSharp
private void startReceiving () private void startReceiving ()
{ {
if (_readyState != WebSocketState.OPEN)
return;
_exitReceiving = new AutoResetEvent (false); _exitReceiving = new AutoResetEvent (false);
_receivePong = new AutoResetEvent (false); _receivePong = new AutoResetEvent (false);
Action receive = null; Action receive = null;
receive = () => _stream.ReadFrameAsync ( receive = () => _stream.ReadFrameAsync (
frame => frame => {
{
if (processFrame (frame)) if (processFrame (frame))
receive (); receive ();
else else
@ -1288,26 +1315,6 @@ namespace WebSocketSharp
receive (); receive ();
} }
// As server
private bool validateConnectionRequest (WebSocketContext context)
{
string version;
return context.IsWebSocketRequest &&
validateHostHeader (context.Host) &&
!context.SecWebSocketKey.IsNullOrEmpty () &&
((version = context.SecWebSocketVersion) != null && version == _version) &&
validateCookies (context.CookieCollection, _cookies);
}
// As client
private bool validateConnectionResponse (HandshakeResponse response)
{
string accept, version;
return response.IsWebSocketResponse &&
((accept = response.Headers ["Sec-WebSocket-Accept"]) != null && accept == createResponseKey ()) &&
((version = response.Headers ["Sec-WebSocket-Version"]) == null || version == _version);
}
// As server // As server
private bool validateCookies (CookieCollection request, CookieCollection response) private bool validateCookies (CookieCollection request, CookieCollection response)
{ {
@ -1377,15 +1384,37 @@ namespace WebSocketSharp
internal void ConnectAsServer () internal void ConnectAsServer ()
{ {
try { try {
if (acceptHandshake ()) if (acceptHandshake ()) {
_readyState = WebSocketState.OPEN;
open (); open ();
}
} }
catch (Exception ex) { catch (Exception ex) {
processException ( processException (
ex, "An exception has occurred while connecting or opening."); ex, "An exception has occurred while connecting.");
} }
} }
// As client
internal static string CreateBase64Key ()
{
var src = new byte [16];
var rand = new Random ();
rand.NextBytes (src);
return Convert.ToBase64String (src);
}
internal static string CreateResponseKey (string base64Key)
{
var buffer = new StringBuilder (base64Key, 64);
buffer.Append (_guid);
SHA1 sha1 = new SHA1CryptoServiceProvider ();
var src = sha1.ComputeHash (Encoding.UTF8.GetBytes (buffer.ToString ()));
return Convert.ToBase64String (src);
}
internal bool Ping (byte [] frameAsBytes, int timeOut) internal bool Ping (byte [] frameAsBytes, int timeOut)
{ {
return send (frameAsBytes) && return send (frameAsBytes) &&
@ -1571,7 +1600,8 @@ namespace WebSocketSharp
return; return;
} }
connect (); if (connect ())
open ();
} }
/// <summary> /// <summary>
@ -1590,8 +1620,13 @@ namespace WebSocketSharp
return; return;
} }
Action connector = connect; Func<bool> connector = connect;
connector.BeginInvoke (ar => connector.EndInvoke (ar), null); connector.BeginInvoke (
ar => {
if (connector.EndInvoke (ar))
open ();
},
null);
} }
/// <summary> /// <summary>