Modified receiving handshake and frame

This commit is contained in:
sta 2013-11-11 17:17:27 +09:00
parent 8595d6b15c
commit d3ba02367e
5 changed files with 134 additions and 88 deletions

View File

@ -367,11 +367,11 @@ namespace WebSocketSharp
/// A <see cref="char"/> to compare. /// A <see cref="char"/> to compare.
/// </param> /// </param>
/// <param name="action"> /// <param name="action">
/// An Action&lt;int&gt; delegate that references the method(s) called at the same time as when comparing. /// An Action&lt;int&gt; 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"/>. /// An <see cref="int"/> parameter to pass to the method(s) is <paramref name="value"/>.
/// </param> /// </param>
/// <exception cref="ArgumentOutOfRangeException"> /// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="value"/> is less than 0, or greater than 255. /// <paramref name="value"/> is not between 0 and 255.
/// </exception> /// </exception>
internal static bool EqualsWith (this int value, char c, Action<int> action) internal static bool EqualsWith (this int value, char c, Action<int> action)
{ {
@ -407,15 +407,27 @@ namespace WebSocketSharp
: original; : original;
} }
internal static string GetErrorMessage (this CloseStatusCode code) internal static string GetMessage (this CloseStatusCode code)
{ {
return code == CloseStatusCode.INCORRECT_DATA return code == CloseStatusCode.PROTOCOL_ERROR
? "A WebSocket protocol error has occurred."
: code == CloseStatusCode.INCORRECT_DATA
? "An incorrect data has been received." ? "An incorrect data has been received."
: code == CloseStatusCode.ABNORMAL
? "An exception has occurred."
: code == CloseStatusCode.INCONSISTENT_DATA : code == CloseStatusCode.INCONSISTENT_DATA
? "An inconsistent data has been received." ? "An inconsistent data has been received."
: code == CloseStatusCode.POLICY_VIOLATION
? "A policy violation data has been received."
: code == CloseStatusCode.TOO_BIG : code == CloseStatusCode.TOO_BIG
? "A too big data has been received." ? "A too big data has been received."
: "A WebSocket exception has occured."; : 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) internal static string GetNameInternal (this string nameAndValue, string separator)
@ -426,17 +438,6 @@ namespace WebSocketSharp
: null; : 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) internal static string GetValueInternal (this string nameAndValue, string separator)
{ {
int i = nameAndValue.IndexOf (separator); int i = nameAndValue.IndexOf (separator);
@ -791,9 +792,9 @@ namespace WebSocketSharp
internal static void WriteBytes (this Stream stream, byte [] value) 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);
} }
} }

View File

@ -505,14 +505,14 @@ namespace WebSocketSharp
// As server // As server
private bool acceptHandshake () private bool acceptHandshake ()
{ {
_logger.Debug (String.Format ("A WebSocket connection request from {0}:\n{1}", _logger.Debug (String.Format (
_context.UserEndPoint, _context)); "A WebSocket connection request from {0}:\n{1}", _context.UserEndPoint, _context));
if (!validateConnectionRequest (_context)) if (!validateConnectionRequest (_context))
{ {
var msg = "Invalid WebSocket connection request."; _logger.Error ("An invalid WebSocket connection request.");
_logger.Error (msg);
error (msg); error ("An error has occurred while handshaking.");
Close (HttpStatusCode.BadRequest); Close (HttpStatusCode.BadRequest);
return false; return false;
@ -542,11 +542,11 @@ namespace WebSocketSharp
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED) if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
return; return;
_logger.Trace ("Start closing handshake.");
_readyState = WebSocketState.CLOSING; _readyState = WebSocketState.CLOSING;
} }
_logger.Trace ("Start closing handshake.");
var args = new CloseEventArgs (payload); var args = new CloseEventArgs (payload);
args.WasClean = _client args.WasClean = _client
? close ( ? close (
@ -559,9 +559,9 @@ namespace WebSocketSharp
closeServerResources); closeServerResources);
_readyState = WebSocketState.CLOSED; _readyState = WebSocketState.CLOSED;
OnClose.Emit (this, args);
_logger.Trace ("End closing handshake."); _logger.Trace ("End closing handshake.");
OnClose.Emit (this, args);
} }
private bool close (byte [] frameAsBytes, int timeOut, Func<bool> release) private bool close (byte [] frameAsBytes, int timeOut, Func<bool> release)
@ -596,7 +596,7 @@ namespace WebSocketSharp
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
return false; return false;
} }
@ -616,13 +616,13 @@ namespace WebSocketSharp
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
return false; return false;
} }
} }
private bool concatenateFragments (Stream dest) private bool concatenateFragmentsInto (Stream dest)
{ {
while (true) while (true)
{ {
@ -661,7 +661,7 @@ namespace WebSocketSharp
return processCloseFrame (frame); return processCloseFrame (frame);
// ? // ?
return processIncorrectFrame (frame, null); return processUnsupportedFrame (frame, CloseStatusCode.INCORRECT_DATA, null);
} }
return true; return true;
@ -772,23 +772,25 @@ namespace WebSocketSharp
{ {
setClientStream (); setClientStream ();
var res = sendHandshakeRequest (); var res = sendHandshakeRequest ();
var msg = res.IsUnauthorized var err = res.IsUnauthorized
? String.Format ("An HTTP {0} authorization is required.", res.AuthChallenge.Scheme) ? String.Format ("An HTTP {0} authorization is required.", res.AuthChallenge.Scheme)
: !validateConnectionResponse (res) : !validateConnectionResponse (res)
? "Invalid response to this WebSocket connection request." ? "An invalid response to this WebSocket connection request."
: String.Empty; : null;
if (msg.Length > 0) if (err != null)
{ {
_logger.Error (msg); _logger.Error (err);
var msg = "An error has occurred while handshaking.";
error (msg); error (msg);
Close (CloseStatusCode.ABNORMAL); close (CloseStatusCode.ABNORMAL, msg, false);
return false; return false;
} }
var protocol = res.Headers ["Sec-WebSocket-Protocol"]; var protocol = res.Headers ["Sec-WebSocket-Protocol"];
if (protocol != null && protocol.Length > 0) if (!protocol.IsNullOrEmpty ())
_protocol = protocol; _protocol = protocol;
processRespondedExtensions (res.Headers ["Sec-WebSocket-Extensions"]); processRespondedExtensions (res.Headers ["Sec-WebSocket-Extensions"]);
@ -841,22 +843,33 @@ namespace WebSocketSharp
return true; return true;
} }
private void processException (Exception exception) private void processException (Exception exception, string reason)
{ {
_logger.Fatal (exception.ToString ());
var code = CloseStatusCode.ABNORMAL; var code = CloseStatusCode.ABNORMAL;
var reason = "An exception has occured."; var msg = reason ?? code.GetMessage ();
var msg = reason;
if (exception.GetType () == typeof (WebSocketException)) if (exception.GetType () == typeof (WebSocketException))
{ {
var wsex = (WebSocketException) exception; var wsex = (WebSocketException) exception;
code = wsex.Code; code = wsex.Code;
reason = wsex.Message; 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); error (msg);
if (_readyState == WebSocketState.CONNECTING && !_client)
Close (HttpStatusCode.BadRequest);
else
close (code, reason, false); close (code, reason, false);
} }
@ -872,7 +885,7 @@ namespace WebSocketSharp
using (var concatenated = new MemoryStream ()) using (var concatenated = new MemoryStream ())
{ {
concatenated.WriteBytes (first.PayloadData.ApplicationData); concatenated.WriteBytes (first.PayloadData.ApplicationData);
if (!concatenateFragments (concatenated)) if (!concatenateFragmentsInto (concatenated))
return false; return false;
byte [] data; byte [] data;
@ -894,7 +907,10 @@ namespace WebSocketSharp
private bool processFrame (WsFrame frame) private bool processFrame (WsFrame frame)
{ {
return frame.IsCompressed && _compression == CompressionMethod.NONE 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 : frame.IsFragmented
? processFragmentedFrame (frame) ? processFragmentedFrame (frame)
: frame.IsData : frame.IsData
@ -905,16 +921,7 @@ namespace WebSocketSharp
? processPongFrame () ? processPongFrame ()
: frame.IsClose : frame.IsClose
? processCloseFrame (frame) ? processCloseFrame (frame)
: processIncorrectFrame (frame, null); : processUnsupportedFrame (frame, CloseStatusCode.POLICY_VIOLATION, 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;
} }
private bool processPingFrame (WsFrame frame) private bool processPingFrame (WsFrame frame)
@ -979,6 +986,14 @@ namespace WebSocketSharp
_compression = CompressionMethod.NONE; _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 // As client
private HandshakeResponse receiveHandshakeResponse () private HandshakeResponse receiveHandshakeResponse ()
{ {
@ -1049,7 +1064,7 @@ namespace WebSocketSharp
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
} }
return sent; return sent;
@ -1075,7 +1090,7 @@ namespace WebSocketSharp
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
} }
finally { finally {
if (compressed) if (compressed)
@ -1101,7 +1116,7 @@ namespace WebSocketSharp
catch (Exception ex) catch (Exception ex)
{ {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
} }
}; };
@ -1121,7 +1136,7 @@ namespace WebSocketSharp
catch (Exception ex) catch (Exception ex)
{ {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
} }
}; };
@ -1244,7 +1259,8 @@ namespace WebSocketSharp
else else
_exitReceiving.Set (); _exitReceiving.Set ();
}, },
processException); ex => processException (
ex, "An exception has occurred while receiving a message."));
receive (); receive ();
} }
@ -1357,7 +1373,7 @@ namespace WebSocketSharp
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
} }
} }
} }
@ -1381,7 +1397,7 @@ namespace WebSocketSharp
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
} }
} }
} }
@ -1519,12 +1535,7 @@ namespace WebSocketSharp
open (); open ();
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); processException (ex, "An exception has occurred while connecting or opening.");
error ("An exception has occured.");
if (_client)
Close (CloseStatusCode.ABNORMAL);
else
Close (HttpStatusCode.BadRequest);
} }
} }
@ -1808,7 +1819,7 @@ namespace WebSocketSharp
ex => ex =>
{ {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
error ("An exception has occured."); error ("An exception has occurred.");
}); });
} }

View File

@ -44,7 +44,7 @@ namespace WebSocketSharp
} }
internal WebSocketException (CloseStatusCode code) internal WebSocketException (CloseStatusCode code)
: this (code, code.GetReason ()) : this (code, code.GetMessage ())
{ {
} }
@ -54,7 +54,7 @@ namespace WebSocketSharp
} }
internal WebSocketException (CloseStatusCode code, string reason) internal WebSocketException (CloseStatusCode code, string reason)
: base (reason) : base (reason ?? code.GetMessage ())
{ {
Code = code; Code = code;
} }

View File

@ -459,7 +459,8 @@ namespace WebSocketSharp
{ {
// Check if allowable payload data length. // Check if allowable payload data length.
if (payloadLen > 126 && dataLen > PayloadData.MaxLength) 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 data = payloadLen > 126
? stream.ReadBytes ((long) dataLen, 1024) ? stream.ReadBytes ((long) dataLen, 1024)

View File

@ -32,6 +32,7 @@ using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Threading;
using WebSocketSharp.Net; using WebSocketSharp.Net;
using WebSocketSharp.Net.Security; using WebSocketSharp.Net.Security;
@ -42,6 +43,7 @@ namespace WebSocketSharp
#region Private Const Fields #region Private Const Fields
private const int _handshakeLimitLen = 8192; private const int _handshakeLimitLen = 8192;
private const int _handshakeTimeout = 90000;
#endregion #endregion
@ -181,8 +183,23 @@ namespace WebSocketSharp
public string [] ReadHandshake () public string [] ReadHandshake ()
{ {
var read = false; var read = false;
var exception = false;
var buffer = new List<byte> (); var buffer = new List<byte> ();
Action<int> add = i => buffer.Add ((byte) i); Action<int> add = i => buffer.Add ((byte) i);
var timeout = false;
var timer = new Timer (
state =>
{
timeout = true;
_innerStream.Close ();
},
null,
_handshakeTimeout,
-1);
try {
while (buffer.Count < _handshakeLimitLen) while (buffer.Count < _handshakeLimitLen)
{ {
if (_innerStream.ReadByte ().EqualsWith ('\r', add) && if (_innerStream.ReadByte ().EqualsWith ('\r', add) &&
@ -194,9 +211,25 @@ namespace WebSocketSharp
break; break;
} }
} }
}
catch {
exception = true;
}
finally {
timer.Change (-1, -1);
timer.Dispose ();
}
if (!read) var reason = timeout
throw new WebSocketException ("The length of the handshake is greater than the limit length."); ? "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 ()) return Encoding.UTF8.GetString (buffer.ToArray ())
.Replace ("\r\n", "\n") .Replace ("\r\n", "\n")