diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs index bc0eb04b..d5a25717 100644 --- a/websocket-sharp/Ext.cs +++ b/websocket-sharp/Ext.cs @@ -367,11 +367,11 @@ namespace WebSocketSharp /// A to compare. /// /// - /// An Action<int> delegate that references the method(s) called at the same time as when comparing. + /// An Action<int> delegate that references the method(s) called at the same time as comparing. /// An parameter to pass to the method(s) is . /// /// - /// is less than 0, or greater than 255. + /// is not between 0 and 255. /// internal static bool EqualsWith (this int value, char c, Action action) { @@ -407,15 +407,27 @@ namespace WebSocketSharp : original; } - internal static string GetErrorMessage (this CloseStatusCode code) + internal static string GetMessage (this CloseStatusCode code) { - return code == CloseStatusCode.INCORRECT_DATA - ? "An incorrect data has been received." - : code == CloseStatusCode.INCONSISTENT_DATA - ? "An inconsistent data has been received." - : code == CloseStatusCode.TOO_BIG - ? "A too big data has been received." - : "A WebSocket exception has occured."; + return code == CloseStatusCode.PROTOCOL_ERROR + ? "A WebSocket protocol error has occurred." + : code == CloseStatusCode.INCORRECT_DATA + ? "An incorrect data has been received." + : code == CloseStatusCode.ABNORMAL + ? "An exception has occurred." + : code == CloseStatusCode.INCONSISTENT_DATA + ? "An inconsistent data has been received." + : code == CloseStatusCode.POLICY_VIOLATION + ? "A policy violation data has been received." + : code == CloseStatusCode.TOO_BIG + ? "A too big data has been received." + : code == CloseStatusCode.IGNORE_EXTENSION + ? "WebSocket client did not receive expected extension(s)." + : code == CloseStatusCode.SERVER_ERROR + ? "WebSocket server got an internal error." + : code == CloseStatusCode.TLS_HANDSHAKE_FAILURE + ? "An error has occurred while handshaking." + : String.Empty; } internal static string GetNameInternal (this string nameAndValue, string separator) @@ -426,17 +438,6 @@ namespace WebSocketSharp : null; } - internal static string GetReason (this CloseStatusCode code) - { - return code == CloseStatusCode.ABNORMAL - ? "A WebSocket exception has occured." - : code == CloseStatusCode.TOO_BIG - ? String.Format ( - "The payload data length is greater than the allowable length ({0} bytes).", - PayloadData.MaxLength) - : String.Empty; - } - internal static string GetValueInternal (this string nameAndValue, string separator) { int i = nameAndValue.IndexOf (separator); @@ -791,9 +792,9 @@ namespace WebSocketSharp internal static void WriteBytes (this Stream stream, byte [] value) { - using (var input = new MemoryStream (value)) + using (var src = new MemoryStream (value)) { - input.CopyTo (stream); + src.CopyTo (stream); } } diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 05387de7..534a981c 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -505,14 +505,14 @@ namespace WebSocketSharp // As server private bool acceptHandshake () { - _logger.Debug (String.Format ("A WebSocket connection request from {0}:\n{1}", - _context.UserEndPoint, _context)); + _logger.Debug (String.Format ( + "A WebSocket connection request from {0}:\n{1}", _context.UserEndPoint, _context)); if (!validateConnectionRequest (_context)) { - var msg = "Invalid WebSocket connection request."; - _logger.Error (msg); - error (msg); + _logger.Error ("An invalid WebSocket connection request."); + + error ("An error has occurred while handshaking."); Close (HttpStatusCode.BadRequest); return false; @@ -542,11 +542,11 @@ namespace WebSocketSharp if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED) return; - _logger.Trace ("Start closing handshake."); - _readyState = WebSocketState.CLOSING; } + _logger.Trace ("Start closing handshake."); + var args = new CloseEventArgs (payload); args.WasClean = _client ? close ( @@ -559,9 +559,9 @@ namespace WebSocketSharp closeServerResources); _readyState = WebSocketState.CLOSED; + OnClose.Emit (this, args); _logger.Trace ("End closing handshake."); - OnClose.Emit (this, args); } private bool close (byte [] frameAsBytes, int timeOut, Func release) @@ -596,7 +596,7 @@ namespace WebSocketSharp } catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); return false; } @@ -616,13 +616,13 @@ namespace WebSocketSharp } catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); return false; } } - private bool concatenateFragments (Stream dest) + private bool concatenateFragmentsInto (Stream dest) { while (true) { @@ -661,7 +661,7 @@ namespace WebSocketSharp return processCloseFrame (frame); // ? - return processIncorrectFrame (frame, null); + return processUnsupportedFrame (frame, CloseStatusCode.INCORRECT_DATA, null); } return true; @@ -772,23 +772,25 @@ namespace WebSocketSharp { setClientStream (); var res = sendHandshakeRequest (); - var msg = res.IsUnauthorized + var err = res.IsUnauthorized ? String.Format ("An HTTP {0} authorization is required.", res.AuthChallenge.Scheme) : !validateConnectionResponse (res) - ? "Invalid response to this WebSocket connection request." - : String.Empty; + ? "An invalid response to this WebSocket connection request." + : null; - if (msg.Length > 0) + if (err != null) { - _logger.Error (msg); + _logger.Error (err); + + var msg = "An error has occurred while handshaking."; error (msg); - Close (CloseStatusCode.ABNORMAL); + close (CloseStatusCode.ABNORMAL, msg, false); return false; } var protocol = res.Headers ["Sec-WebSocket-Protocol"]; - if (protocol != null && protocol.Length > 0) + if (!protocol.IsNullOrEmpty ()) _protocol = protocol; processRespondedExtensions (res.Headers ["Sec-WebSocket-Extensions"]); @@ -841,23 +843,34 @@ namespace WebSocketSharp return true; } - private void processException (Exception exception) + private void processException (Exception exception, string reason) { - _logger.Fatal (exception.ToString ()); - var code = CloseStatusCode.ABNORMAL; - var reason = "An exception has occured."; - var msg = reason; + var msg = reason ?? code.GetMessage (); + if (exception.GetType () == typeof (WebSocketException)) { var wsex = (WebSocketException) exception; code = wsex.Code; reason = wsex.Message; - msg = code.GetErrorMessage (); + } + + if (code == CloseStatusCode.ABNORMAL) + { + _logger.Fatal (exception.ToString ()); + reason = msg; + } + else + { + _logger.Error (reason); + msg = code.GetMessage (); } error (msg); - close (code, reason, false); + if (_readyState == WebSocketState.CONNECTING && !_client) + Close (HttpStatusCode.BadRequest); + else + close (code, reason, false); } private bool processFragmentedFrame (WsFrame frame) @@ -872,7 +885,7 @@ namespace WebSocketSharp using (var concatenated = new MemoryStream ()) { concatenated.WriteBytes (first.PayloadData.ApplicationData); - if (!concatenateFragments (concatenated)) + if (!concatenateFragmentsInto (concatenated)) return false; byte [] data; @@ -894,7 +907,10 @@ namespace WebSocketSharp private bool processFrame (WsFrame frame) { return frame.IsCompressed && _compression == CompressionMethod.NONE - ? processIncorrectFrame (frame, "A compressed frame without available decompression method.") + ? processUnsupportedFrame ( + frame, + CloseStatusCode.INCORRECT_DATA, + "A compressed data has been received without available decompression method.") : frame.IsFragmented ? processFragmentedFrame (frame) : frame.IsData @@ -905,16 +921,7 @@ namespace WebSocketSharp ? processPongFrame () : frame.IsClose ? processCloseFrame (frame) - : processIncorrectFrame (frame, null); - } - - private bool processIncorrectFrame (WsFrame frame, string reason) - { - _logger.Debug ("Incorrect frame:\n" + frame.PrintToString (false)); - processException (new WebSocketException ( - CloseStatusCode.INCORRECT_DATA, reason ?? String.Empty)); - - return false; + : processUnsupportedFrame (frame, CloseStatusCode.POLICY_VIOLATION, null); } private bool processPingFrame (WsFrame frame) @@ -979,6 +986,14 @@ namespace WebSocketSharp _compression = CompressionMethod.NONE; } + private bool processUnsupportedFrame (WsFrame frame, CloseStatusCode code, string reason) + { + _logger.Debug ("Unsupported frame:\n" + frame.PrintToString (false)); + processException (new WebSocketException (code, reason), null); + + return false; + } + // As client private HandshakeResponse receiveHandshakeResponse () { @@ -1049,7 +1064,7 @@ namespace WebSocketSharp } catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); } return sent; @@ -1075,7 +1090,7 @@ namespace WebSocketSharp } catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); } finally { if (compressed) @@ -1101,7 +1116,7 @@ namespace WebSocketSharp catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); } }; @@ -1121,7 +1136,7 @@ namespace WebSocketSharp catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); } }; @@ -1244,7 +1259,8 @@ namespace WebSocketSharp else _exitReceiving.Set (); }, - processException); + ex => processException ( + ex, "An exception has occurred while receiving a message.")); receive (); } @@ -1357,7 +1373,7 @@ namespace WebSocketSharp } catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); } } } @@ -1381,7 +1397,7 @@ namespace WebSocketSharp } catch (Exception ex) { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); } } } @@ -1519,12 +1535,7 @@ namespace WebSocketSharp open (); } catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); - if (_client) - Close (CloseStatusCode.ABNORMAL); - else - Close (HttpStatusCode.BadRequest); + processException (ex, "An exception has occurred while connecting or opening."); } } @@ -1808,7 +1819,7 @@ namespace WebSocketSharp ex => { _logger.Fatal (ex.ToString ()); - error ("An exception has occured."); + error ("An exception has occurred."); }); } diff --git a/websocket-sharp/WebSocketException.cs b/websocket-sharp/WebSocketException.cs index bd7394f5..aa07c74d 100644 --- a/websocket-sharp/WebSocketException.cs +++ b/websocket-sharp/WebSocketException.cs @@ -44,7 +44,7 @@ namespace WebSocketSharp } internal WebSocketException (CloseStatusCode code) - : this (code, code.GetReason ()) + : this (code, code.GetMessage ()) { } @@ -54,7 +54,7 @@ namespace WebSocketSharp } internal WebSocketException (CloseStatusCode code, string reason) - : base (reason) + : base (reason ?? code.GetMessage ()) { Code = code; } diff --git a/websocket-sharp/WsFrame.cs b/websocket-sharp/WsFrame.cs index 7a83ddef..e21bd3ee 100644 --- a/websocket-sharp/WsFrame.cs +++ b/websocket-sharp/WsFrame.cs @@ -459,7 +459,8 @@ namespace WebSocketSharp { // Check if allowable payload data length. if (payloadLen > 126 && dataLen > PayloadData.MaxLength) - throw new WebSocketException (CloseStatusCode.TOO_BIG); + throw new WebSocketException ( + CloseStatusCode.TOO_BIG, "The 'Payload Data' length is greater than the allowable length."); data = payloadLen > 126 ? stream.ReadBytes ((long) dataLen, 1024) diff --git a/websocket-sharp/WsStream.cs b/websocket-sharp/WsStream.cs index 6642ec74..da33859f 100644 --- a/websocket-sharp/WsStream.cs +++ b/websocket-sharp/WsStream.cs @@ -32,6 +32,7 @@ using System.IO; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Threading; using WebSocketSharp.Net; using WebSocketSharp.Net.Security; @@ -42,6 +43,7 @@ namespace WebSocketSharp #region Private Const Fields private const int _handshakeLimitLen = 8192; + private const int _handshakeTimeout = 90000; #endregion @@ -181,22 +183,53 @@ namespace WebSocketSharp public string [] ReadHandshake () { var read = false; + var exception = false; + var buffer = new List (); Action add = i => buffer.Add ((byte) i); - while (buffer.Count < _handshakeLimitLen) - { - if (_innerStream.ReadByte ().EqualsWith ('\r', add) && - _innerStream.ReadByte ().EqualsWith ('\n', add) && - _innerStream.ReadByte ().EqualsWith ('\r', add) && - _innerStream.ReadByte ().EqualsWith ('\n', add)) + + var timeout = false; + var timer = new Timer ( + state => { - read = true; - break; + timeout = true; + _innerStream.Close (); + }, + null, + _handshakeTimeout, + -1); + + try { + while (buffer.Count < _handshakeLimitLen) + { + if (_innerStream.ReadByte ().EqualsWith ('\r', add) && + _innerStream.ReadByte ().EqualsWith ('\n', add) && + _innerStream.ReadByte ().EqualsWith ('\r', add) && + _innerStream.ReadByte ().EqualsWith ('\n', add)) + { + read = true; + break; + } } } + catch { + exception = true; + } + finally { + timer.Change (-1, -1); + timer.Dispose (); + } - if (!read) - throw new WebSocketException ("The length of the handshake is greater than the limit length."); + var reason = timeout + ? "A timeout has occurred while receiving a handshake." + : exception + ? "An exception has occurred while receiving a handshake." + : !read + ? "A handshake length is greater than the limit length." + : null; + + if (reason != null) + throw new WebSocketException (reason); return Encoding.UTF8.GetString (buffer.ToArray ()) .Replace ("\r\n", "\n")