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.
/// </param>
/// <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"/>.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="value"/> is less than 0, or greater than 255.
/// <paramref name="value"/> is not between 0 and 255.
/// </exception>
internal static bool EqualsWith (this int value, char c, Action<int> 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);
}
}

View File

@ -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<bool> 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.");
});
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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<byte> ();
Action<int> 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")