Refactored WebSocket.cs

This commit is contained in:
sta 2014-07-17 21:44:10 +09:00
parent e7c9b19bf0
commit a18993f2be
2 changed files with 187 additions and 175 deletions

View File

@ -261,12 +261,11 @@ namespace WebSocketSharp
/// </value>
public IEnumerable<Cookie> Cookies {
get {
lock (_cookies.SyncRoot) {
lock (_cookies.SyncRoot)
foreach (Cookie cookie in _cookies)
yield return cookie;
}
}
}
/// <summary>
/// Gets the credentials for the HTTP authentication (Basic/Digest).
@ -606,13 +605,13 @@ namespace WebSocketSharp
if (extensions != null && extensions.Length > 0)
acceptSecWebSocketExtensionsHeader (extensions);
return send (createHandshakeResponse ());
return sendHandshakeResponse (createHandshakeResponse ());
}
private bool acceptPingFrame (WebSocketFrame frame)
{
var mask = _client ? Mask.Mask : Mask.Unmask;
if (send (WebSocketFrame.CreatePongFrame (mask, frame.PayloadData)))
if (sendWebSocketFrame (WebSocketFrame.CreatePongFrame (mask, frame.PayloadData)))
_logger.Trace ("Returned a Pong.");
return true;
@ -700,7 +699,7 @@ namespace WebSocketSharp
var headers = response.Headers;
return response.IsUnauthorized
? String.Format (
"HTTP {0} authorization is required.", response.AuthenticationChallenge.Scheme)
"HTTP {0} authentication is required.", response.AuthenticationChallenge.Scheme)
: !response.IsWebSocketResponse
? "Not WebSocket connection response."
: !validateSecWebSocketAcceptHeader (headers["Sec-WebSocket-Accept"])
@ -776,11 +775,12 @@ namespace WebSocketSharp
}
}
private bool closeHandshake (byte [] frame, int timeout, Action release)
private bool closeHandshake (byte[] data, int millisecondsTimeout, Action release)
{
var sent = frame != null && _stream.WriteBytes (frame);
var received = timeout == 0 ||
(sent && _exitReceiving != null && _exitReceiving.WaitOne (timeout));
var sent = data != null && _stream.WriteBytes (data);
var received =
millisecondsTimeout == 0 ||
(sent && _exitReceiving != null && _exitReceiving.WaitOne (millisecondsTimeout));
release ();
if (_receivePong != null) {
@ -1045,57 +1045,6 @@ namespace WebSocketSharp
}
}
// As client
private HttpResponse receiveHandshakeResponse ()
{
var res = _stream.ReadHttpResponse (90000);
_logger.Debug ("A response to this WebSocket connection request:\n" + res.ToString ());
return res;
}
private bool send (byte [] frame)
{
lock (_forConn) {
if (_readyState != WebSocketState.Open) {
_logger.Warn ("Sending has been interrupted.");
return false;
}
return _stream.WriteBytes (frame);
}
}
// As client
private void send (HttpRequest request)
{
_logger.Debug (
String.Format ("A WebSocket connection request to {0}:\n{1}", _uri, request));
_stream.WriteBytes (request.ToByteArray ());
}
// As server
private bool send (HttpResponse response)
{
_logger.Debug (
"A response to the WebSocket connection request:\n" + response.ToString ());
return _stream.WriteBytes (response.ToByteArray ());
}
private bool send (WebSocketFrame frame)
{
lock (_forConn) {
if (_readyState != WebSocketState.Open) {
_logger.Warn ("Sending has been interrupted.");
return false;
}
return _stream.WriteBytes (frame.ToByteArray ());
}
}
private bool send (Opcode opcode, byte[] data)
{
lock (_forSend) {
@ -1108,7 +1057,8 @@ namespace WebSocketSharp
}
var mask = _client ? Mask.Mask : Mask.Unmask;
sent = send (WebSocketFrame.CreateFrame (Fin.Final, opcode, mask, data, compressed));
sent = sendWebSocketFrame (
WebSocketFrame.CreateFrame (Fin.Final, opcode, mask, data, compressed));
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
@ -1196,43 +1146,47 @@ namespace WebSocketSharp
var rem = (int) (len % FragmentLength);
var times = rem == 0 ? quo - 2 : quo - 1;
byte [] buffer = null;
byte[] buff = null;
// Not fragmented
if (quo == 0) {
buffer = new byte [rem];
return stream.Read (buffer, 0, rem) == rem &&
send (WebSocketFrame.CreateFrame (Fin.Final, opcode, mask, buffer, compressed));
buff = new byte[rem];
return stream.Read (buff, 0, rem) == rem &&
sendWebSocketFrame (
WebSocketFrame.CreateFrame (Fin.Final, opcode, mask, buff, compressed));
}
buffer = new byte [FragmentLength];
buff = new byte[FragmentLength];
// First
if (stream.Read (buffer, 0, FragmentLength) != FragmentLength ||
!send (WebSocketFrame.CreateFrame (Fin.More, opcode, mask, buffer, compressed)))
if (stream.Read (buff, 0, FragmentLength) != FragmentLength ||
!sendWebSocketFrame (
WebSocketFrame.CreateFrame (Fin.More, opcode, mask, buff, compressed)))
return false;
// Mid
for (long i = 0; i < times; i++) {
if (stream.Read (buffer, 0, FragmentLength) != FragmentLength ||
!send (WebSocketFrame.CreateFrame (Fin.More, Opcode.Cont, mask, buffer, compressed)))
if (stream.Read (buff, 0, FragmentLength) != FragmentLength ||
!sendWebSocketFrame (
WebSocketFrame.CreateFrame (Fin.More, Opcode.Cont, mask, buff, compressed)))
return false;
}
// Final
var tmpLen = FragmentLength;
if (rem != 0)
buffer = new byte [tmpLen = rem];
buff = new byte[tmpLen = rem];
return stream.Read (buffer, 0, tmpLen) == tmpLen &&
send (WebSocketFrame.CreateFrame (Fin.Final, Opcode.Cont, mask, buffer, compressed));
return stream.Read (buff, 0, tmpLen) == tmpLen &&
sendWebSocketFrame (
WebSocketFrame.CreateFrame (Fin.Final, Opcode.Cont, mask, buff, compressed));
}
// As client
private HttpResponse sendHandshakeRequest ()
{
var req = createHandshakeRequest ();
var res = sendHandshakeRequest (req);
var res = sendHandshakeRequest (req, 90000);
if (res.IsUnauthorized) {
_authChallenge = res.AuthenticationChallenge;
if (_credentials != null &&
@ -1245,7 +1199,7 @@ namespace WebSocketSharp
var authRes = new AuthenticationResponse (_authChallenge, _credentials, _nonceCount);
_nonceCount = authRes.NonceCount;
req.Headers["Authorization"] = authRes.ToString ();
res = sendHandshakeRequest (req);
res = sendHandshakeRequest (req, 15000);
}
}
@ -1253,17 +1207,60 @@ namespace WebSocketSharp
}
// As client
private HttpResponse sendHandshakeRequest (HttpRequest request)
private HttpResponse sendHandshakeRequest (HttpRequest request, int millisecondsTimeout)
{
send (request);
return receiveHandshakeResponse ();
_logger.Debug (
String.Format ("A WebSocket connection request to {0}:\n{1}", _uri, request));
var res = _stream.SendHttpRequest (request, millisecondsTimeout);
_logger.Debug ("A response to this WebSocket connection request:\n" + res.ToString ());
return res;
}
// As server
private bool sendHandshakeResponse (HttpResponse response)
{
_logger.Debug (
"A response to the WebSocket connection request:\n" + response.ToString ());
return _stream.WriteHttp (response);
}
private bool sendWebSocketFrame (byte[] data)
{
lock (_forConn) {
if (_readyState != WebSocketState.Open) {
_logger.Warn ("Sending has been interrupted.");
return false;
}
return _stream.WriteBytes (data);
}
}
private bool sendWebSocketFrame (WebSocketFrame frame)
{
lock (_forConn) {
if (_readyState != WebSocketState.Open) {
_logger.Warn ("Sending has been interrupted.");
return false;
}
return _stream.WriteWebSocketFrame (frame);
}
}
// As client
private void setClientStream ()
{
var proxy = _proxyUri != null;
_tcpClient = proxy
? new TcpClient (_proxyUri.DnsSafeHost, _proxyUri.Port)
: new TcpClient (_uri.DnsSafeHost, _uri.Port);
_stream = WebSocketStream.CreateClientStream (
_uri, _proxyUri, _proxyCredentials, _secure, _certValidationCallback, out _tcpClient);
_tcpClient, proxy, _uri, _proxyCredentials, _secure, _certValidationCallback);
}
private void startReceiving ()
@ -1376,7 +1373,7 @@ namespace WebSocketSharp
{
_readyState = WebSocketState.Closing;
send (response);
sendHandshakeResponse (response);
closeServerResources ();
_readyState = WebSocketState.Closed;
@ -1389,7 +1386,7 @@ namespace WebSocketSharp
}
// As server
internal void Close (CloseEventArgs e, byte [] frame, int timeout)
internal void Close (CloseEventArgs e, byte[] data, int millisecondsTimeout)
{
lock (_forConn) {
if (_readyState == WebSocketState.Closing || _readyState == WebSocketState.Closed) {
@ -1400,7 +1397,7 @@ namespace WebSocketSharp
_readyState = WebSocketState.Closing;
}
e.WasClean = closeHandshake (frame, timeout, closeServerResources);
e.WasClean = closeHandshake (data, millisecondsTimeout, closeServerResources);
_readyState = WebSocketState.Closed;
try {
@ -1437,22 +1434,22 @@ namespace WebSocketSharp
internal static string CreateResponseKey (string base64Key)
{
var buffer = new StringBuilder (base64Key, 64);
buffer.Append (_guid);
var buff = new StringBuilder (base64Key, 64);
buff.Append (_guid);
SHA1 sha1 = new SHA1CryptoServiceProvider ();
var src = sha1.ComputeHash (Encoding.UTF8.GetBytes (buffer.ToString ()));
var src = sha1.ComputeHash (Encoding.UTF8.GetBytes (buff.ToString ()));
return Convert.ToBase64String (src);
}
internal bool Ping (byte [] frame, int timeout)
internal bool Ping (byte[] data, int millisecondsTimeout)
{
try {
AutoResetEvent pong;
return _readyState == WebSocketState.Open &&
send (frame) &&
sendWebSocketFrame (data) &&
(pong = _receivePong) != null &&
pong.WaitOne (timeout);
pong.WaitOne (millisecondsTimeout);
}
catch (Exception ex) {
_logger.Fatal ("An exception has occurred while Ping:\n" + ex.ToString ());
@ -1537,15 +1534,15 @@ namespace WebSocketSharp
}
/// <summary>
/// Closes the WebSocket connection with the specified <see cref="ushort"/>, and releases all
/// associated resources.
/// Closes the WebSocket connection with the specified <see cref="ushort"/>,
/// and releases all associated resources.
/// </summary>
/// <remarks>
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/> isn't in the
/// allowable range of the WebSocket close status code.
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/>
/// isn't in the allowable range of the WebSocket close status code.
/// </remarks>
/// <param name="code">
/// A <see cref="ushort"/> that represents the status code indicating the reason for closure.
/// A <see cref="ushort"/> that represents the status code indicating the reason for the close.
/// </param>
public void Close (ushort code)
{
@ -1553,12 +1550,12 @@ namespace WebSocketSharp
}
/// <summary>
/// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/>, and
/// releases all associated resources.
/// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/>,
/// and releases all associated resources.
/// </summary>
/// <param name="code">
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code indicating
/// the reason for closure.
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code
/// indicating the reason for the close.
/// </param>
public void Close (CloseStatusCode code)
{
@ -1566,19 +1563,19 @@ namespace WebSocketSharp
}
/// <summary>
/// Closes the WebSocket connection with the specified <see cref="ushort"/> and
/// <see cref="string"/>, and releases all associated resources.
/// Closes the WebSocket connection with the specified <see cref="ushort"/>
/// and <see cref="string"/>, and releases all associated resources.
/// </summary>
/// <remarks>
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/> isn't in the
/// allowable range of the WebSocket close status code or the size of <paramref name="reason"/>
/// is greater than 123 bytes.
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/>
/// isn't in the allowable range of the WebSocket close status code or the size
/// of <paramref name="reason"/> is greater than 123 bytes.
/// </remarks>
/// <param name="code">
/// A <see cref="ushort"/> that represents the status code indicating the reason for closure.
/// A <see cref="ushort"/> that represents the status code indicating the reason for the close.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that represents the reason for closure.
/// A <see cref="string"/> that represents the reason for the close.
/// </param>
public void Close (ushort code, string reason)
{
@ -1599,19 +1596,19 @@ namespace WebSocketSharp
}
/// <summary>
/// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/> and
/// <see cref="string"/>, and releases all associated resources.
/// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/>
/// and <see cref="string"/>, and releases all associated resources.
/// </summary>
/// <remarks>
/// This method emits a <see cref="OnError"/> event if the size of <paramref name="reason"/> is
/// greater than 123 bytes.
/// This method emits a <see cref="OnError"/> event if the size
/// of <paramref name="reason"/> is greater than 123 bytes.
/// </remarks>
/// <param name="code">
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code indicating
/// the reason for closure.
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code
/// indicating the reason for the close.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that represents the reason for closure.
/// A <see cref="string"/> that represents the reason for the close.
/// </param>
public void Close (CloseStatusCode code, string reason)
{
@ -1659,12 +1656,12 @@ namespace WebSocketSharp
/// This method doesn't wait for the close to be complete.
/// </para>
/// <para>
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/> isn't in the
/// allowable range of the WebSocket close status code.
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/>
/// isn't in the allowable range of the WebSocket close status code.
/// </para>
/// </remarks>
/// <param name="code">
/// A <see cref="ushort"/> that represents the status code indicating the reason for closure.
/// A <see cref="ushort"/> that represents the status code indicating the reason for the close.
/// </param>
public void CloseAsync (ushort code)
{
@ -1679,8 +1676,8 @@ namespace WebSocketSharp
/// This method doesn't wait for the close to be complete.
/// </remarks>
/// <param name="code">
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code indicating
/// the reason for closure.
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code
/// indicating the reason for the close.
/// </param>
public void CloseAsync (CloseStatusCode code)
{
@ -1688,8 +1685,8 @@ namespace WebSocketSharp
}
/// <summary>
/// Closes the WebSocket connection asynchronously with the specified <see cref="ushort"/> and
/// <see cref="string"/>, and releases all associated resources.
/// Closes the WebSocket connection asynchronously with the specified <see cref="ushort"/>
/// and <see cref="string"/>, and releases all associated resources.
/// </summary>
/// <remarks>
/// <para>
@ -1702,10 +1699,10 @@ namespace WebSocketSharp
/// </para>
/// </remarks>
/// <param name="code">
/// A <see cref="ushort"/> that represents the status code indicating the reason for closure.
/// A <see cref="ushort"/> that represents the status code indicating the reason for the close.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that represents the reason for closure.
/// A <see cref="string"/> that represents the reason for the close.
/// </param>
public void CloseAsync (ushort code, string reason)
{
@ -1735,16 +1732,16 @@ namespace WebSocketSharp
/// This method doesn't wait for the close to be complete.
/// </para>
/// <para>
/// This method emits a <see cref="OnError"/> event if the size of <paramref name="reason"/>
/// is greater than 123 bytes.
/// This method emits a <see cref="OnError"/> event if the size
/// of <paramref name="reason"/> is greater than 123 bytes.
/// </para>
/// </remarks>
/// <param name="code">
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code indicating
/// the reason for closure.
/// One of the <see cref="CloseStatusCode"/> enum values, represents the status code
/// indicating the reason for the close.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that represents the reason for closure.
/// A <see cref="string"/> that represents the reason for the close.
/// </param>
public void CloseAsync (CloseStatusCode code, string reason)
{

View File

@ -182,23 +182,29 @@ namespace WebSocketSharp
return readHttp<HttpResponse> (stream, HttpResponse.Parse, millisecondsTimeout);
}
private static bool writeBytes (Stream stream, byte[] data)
{
try {
stream.Write (data, 0, data.Length);
return true;
}
catch {
return false;
}
}
#endregion
#region Internal Methods
internal static WebSocketStream CreateClientStream (
TcpClient tcpClient,
bool proxy,
Uri targetUri,
Uri proxyUri,
NetworkCredential proxyCredentials,
bool secure,
System.Net.Security.RemoteCertificateValidationCallback validationCallback,
out TcpClient tcpClient)
System.Net.Security.RemoteCertificateValidationCallback validationCallback)
{
var proxy = proxyUri != null;
tcpClient = proxy
? new TcpClient (proxyUri.DnsSafeHost, proxyUri.Port)
: new TcpClient (targetUri.DnsSafeHost, targetUri.Port);
var netStream = tcpClient.GetStream ();
if (proxy) {
var req = HttpRequest.CreateConnectRequest (targetUri);
@ -270,17 +276,26 @@ namespace WebSocketSharp
WebSocketFrame.ParseAsync (_innerStream, true, completed, error);
}
internal HttpResponse SendHttpRequest (HttpRequest request, int millisecondsTimeout)
{
return sendHttpRequest (_innerStream, request, millisecondsTimeout);
}
internal bool WriteBytes (byte[] data)
{
lock (_forWrite) {
try {
_innerStream.Write (data, 0, data.Length);
return true;
}
catch {
return false;
lock (_forWrite)
return writeBytes (_innerStream, data);
}
internal bool WriteHttp (HttpBase http)
{
return writeBytes (_innerStream, http.ToByteArray ());
}
internal bool WriteWebSocketFrame (WebSocketFrame frame)
{
lock (_forWrite)
return writeBytes (_innerStream, frame.ToByteArray ());
}
#endregion