diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs
index 67b93795..fc8eabb9 100644
--- a/websocket-sharp/Ext.cs
+++ b/websocket-sharp/Ext.cs
@@ -164,6 +164,59 @@ namespace WebSocketSharp
}
}
+ internal static string CheckIfValidCloseData (this byte [] data)
+ {
+ return data.Length > 125
+ ? "The payload length of a Close frame must be 125 bytes or less."
+ : null;
+ }
+
+ internal static string CheckIfValidCloseStatusCode (this ushort code)
+ {
+ return !code.IsCloseStatusCode ()
+ ? "Invalid close status code."
+ : null;
+ }
+
+ internal static string CheckIfValidPingMessage (this string message)
+ {
+ return message != null && message.Length > 0 && Encoding.UTF8.GetBytes (message).Length > 125
+ ? "The payload length of a Ping frame must be 125 bytes or less."
+ : null;
+ }
+
+ internal static string CheckIfValidSendData (this byte [] data)
+ {
+ return data == null
+ ? "'data' must not be null."
+ : null;
+ }
+
+ internal static string CheckIfValidSendData (this string data)
+ {
+ return data == null
+ ? "'data' must not be null."
+ : null;
+ }
+
+ internal static string CheckIfValidServicePath (this string servicePath)
+ {
+ return servicePath == null || servicePath.Length == 0
+ ? "'servicePath' must not be null or empty."
+ : servicePath [0] != '/'
+ ? "'servicePath' not absolute path."
+ : servicePath.IndexOfAny (new [] {'?', '#'}) != -1
+ ? "'servicePath' must not contain either or both query and fragment components."
+ : null;
+ }
+
+ internal static string CheckIfValidSessionID (this string id)
+ {
+ return id == null || id.Length == 0
+ ? "'id' must not be null or empty."
+ : null;
+ }
+
internal static byte [] Compress (this byte [] value, CompressionMethod method)
{
return method == CompressionMethod.DEFLATE
@@ -230,26 +283,26 @@ namespace WebSocketSharp
return value == method.ToCompressionExtension ();
}
- //
- // Determines whether the specified equals the specified ,
- // and invokes the specified Action<int> delegate at the same time.
- //
- //
- // true if equals ; otherwise, false.
- //
- //
- // An to compare.
- //
- //
- // A to compare.
- //
- //
- // An Action<int> delegate that references the method(s) called at the same time as when comparing.
- // An parameter to pass to the method(s) is .
- //
- //
- // is less than 0, or greater than 255.
- //
+ ///
+ /// Determines whether the specified equals the specified ,
+ /// and invokes the specified Action<int> delegate at the same time.
+ ///
+ ///
+ /// true if equals ; otherwise, false.
+ ///
+ ///
+ /// An to compare.
+ ///
+ ///
+ /// A to compare.
+ ///
+ ///
+ /// An Action<int> delegate that references the method(s) called at the same time as when comparing.
+ /// An parameter to pass to the method(s) is .
+ ///
+ ///
+ /// is less than 0, or greater than 255.
+ ///
internal static bool EqualsWith (this int value, char c, Action action)
{
if (value < 0 || value > 255)
@@ -259,6 +312,31 @@ namespace WebSocketSharp
return value == c - 0;
}
+ ///
+ /// Gets the absolute path from the specified .
+ ///
+ ///
+ /// A that contains the absolute path if it is successfully found;
+ /// otherwise, .
+ ///
+ ///
+ /// A that contains a URI to get the absolute path from.
+ ///
+ internal static string GetAbsolutePath (this Uri uri)
+ {
+ if (uri.IsAbsoluteUri)
+ return uri.AbsolutePath;
+
+ var original = uri.OriginalString;
+ if (original [0] != '/')
+ return null;
+
+ var i = original.IndexOfAny (new [] {'?', '#'});
+ return i > 0
+ ? original.Substring (0, i)
+ : original;
+ }
+
internal static string GetNameInternal (this string nameAndValue, string separator)
{
int i = nameAndValue.IndexOf (separator);
@@ -498,6 +576,14 @@ namespace WebSocketSharp
return CompressionMethod.NONE;
}
+ internal static string TrimEndSlash (this string value)
+ {
+ value = value.TrimEnd ('/');
+ return value.Length > 0
+ ? value
+ : "/";
+ }
+
internal static string Unquote (this string value)
{
var start = value.IndexOf ('\"');
@@ -536,7 +622,7 @@ namespace WebSocketSharp
///
public static bool Contains (this string value, params char [] chars)
{
- return chars.Length == 0
+ return chars == null || chars.Length == 0
? true
: value == null || value.Length == 0
? false
@@ -639,35 +725,6 @@ namespace WebSocketSharp
eventHandler (sender, e);
}
- ///
- /// Gets the absolute path from the specified .
- ///
- ///
- /// A that contains the absolute path if gets successfully;
- /// otherwise, .
- ///
- ///
- /// A that contains a URI to get the absolute path from.
- ///
- public static string GetAbsolutePath (this Uri uri)
- {
- if (uri == null)
- return null;
-
- if (uri.IsAbsoluteUri)
- return uri.AbsolutePath;
-
- var uriString = uri.OriginalString;
- var i = uriString.IndexOf ('/');
- if (i != 0)
- return null;
-
- i = uriString.IndexOfAny (new [] {'?', '#'});
- return i > 0
- ? uriString.Substring (0, i)
- : uriString;
- }
-
///
/// Gets the collection of cookies from the specified .
///
@@ -851,25 +908,23 @@ namespace WebSocketSharp
///
///
///
- /// true if is in the allowable range of the WebSocket close status code; otherwise, false.
+ /// true if is in the allowable range of the WebSocket close status code;
+ /// otherwise, false.
///
- ///
+ ///
/// A to test.
///
- public static bool IsCloseStatusCode (this ushort code)
+ public static bool IsCloseStatusCode (this ushort value)
{
- return code < 1000
- ? false
- : code > 4999
- ? false
- : true;
+ return value > 999 && value < 5000;
}
///
/// Determines whether the specified is enclosed in the specified .
///
///
- /// true if is enclosed in ; otherwise, false.
+ /// true if is enclosed in ;
+ /// otherwise, false.
///
///
/// A to test.
@@ -879,9 +934,10 @@ namespace WebSocketSharp
///
public static bool IsEnclosedIn (this string value, char c)
{
- return value == null || value.Length == 0
- ? false
- : value [0] == c && value [value.Length - 1] == c;
+ return value != null &&
+ value.Length > 1 &&
+ value [0] == c &&
+ value [value.Length - 1] == c;
}
///
@@ -1021,44 +1077,6 @@ namespace WebSocketSharp
request.Headers.Contains ("Connection", "Upgrade");
}
- ///
- /// Determines whether the specified is valid absolute path.
- ///
- ///
- /// true if is valid absolute path; otherwise, false.
- ///
- ///
- /// A to test.
- ///
- ///
- /// A that receives a message if is invalid.
- ///
- public static bool IsValidAbsolutePath (this string absPath, out string message)
- {
- if (absPath == null || absPath.Length == 0)
- {
- message = "Must not be null or empty.";
- return false;
- }
-
- var i = absPath.IndexOf ('/');
- if (i != 0)
- {
- message = "Not absolute path: " + absPath;
- return false;
- }
-
- i = absPath.IndexOfAny (new [] {'?', '#'});
- if (i != -1)
- {
- message = "Must not contain either or both query and fragment components: " + absPath;
- return false;
- }
-
- message = String.Empty;
- return true;
- }
-
///
/// Determines whether the specified is a URI string.
///
diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs
index d9f0c200..bff346be 100644
--- a/websocket-sharp/Server/HttpServer.cs
+++ b/websocket-sharp/Server/HttpServer.cs
@@ -134,7 +134,8 @@ namespace WebSocketSharp.Server
set {
if (_listening)
{
- _logger.Error ("The value of Certificate property cannot be changed because the server has already been started.");
+ _logger.Error (
+ "The value of Certificate property cannot be changed because the server has already been started.");
return;
}
@@ -233,7 +234,8 @@ namespace WebSocketSharp.Server
set {
if (_listening)
{
- _logger.Error ("The value of RootPath property cannot be changed because the server has already been started.");
+ _logger.Error (
+ "The value of RootPath property cannot be changed because the server has already been started.");
return;
}
@@ -386,10 +388,9 @@ namespace WebSocketSharp.Server
private bool processWebSocketRequest (HttpListenerContext context)
{
var wsContext = context.AcceptWebSocket ();
- var path = wsContext.Path.UrlDecode ();
IWebSocketServiceHost host;
- if (!_serviceHosts.TryGetServiceHost (path, out host))
+ if (!_serviceHosts.TryGetServiceHost (wsContext.Path, out host))
{
context.Response.StatusCode = (int) HttpStatusCode.NotImplemented;
return false;
@@ -451,26 +452,19 @@ namespace WebSocketSharp.Server
_receiveRequestThread.Start ();
}
- private void stop (ushort code, string reason, bool ignoreArgs)
+ private void stop (ushort code, string reason)
{
- if (!ignoreArgs)
+ var data = code.Append (reason);
+ var msg = data.CheckIfValidCloseData ();
+ if (msg != null)
{
- var data = code.Append (reason);
- if (data.Length > 125)
- {
- _logger.Error (
- String.Format ("The payload length of a Close frame must be 125 bytes or less.\ncode: {0}\nreason: {1}", code, reason));
- return;
- }
+ _logger.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
+ return;
}
_listener.Close ();
_receiveRequestThread.Join (5 * 1000);
- if (ignoreArgs)
- _serviceHosts.Stop ();
- else
- _serviceHosts.Stop (code, reason);
-
+ _serviceHosts.Stop (code, reason);
_listening = false;
}
@@ -481,6 +475,10 @@ namespace WebSocketSharp.Server
///
/// Adds the specified typed WebSocket service with the specified .
///
+ ///
+ /// This method converts to URL-decoded string and
+ /// removes '/' from tail end of .
+ ///
///
/// A that contains an absolute path to the WebSocket service.
///
@@ -490,10 +488,10 @@ namespace WebSocketSharp.Server
public void AddWebSocketService (string servicePath)
where T : WebSocketService, new ()
{
- string msg;
- if (!servicePath.IsValidAbsolutePath (out msg))
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
{
- _logger.Error (msg);
+ _logger.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return;
}
@@ -529,6 +527,10 @@ namespace WebSocketSharp.Server
///
/// Removes the WebSocket service with the specified .
///
+ ///
+ /// This method converts to URL-decoded string and
+ /// removes '/' from tail end of .
+ ///
///
/// true if the WebSocket service is successfully found and removed; otherwise, false.
///
@@ -537,9 +539,10 @@ namespace WebSocketSharp.Server
///
public bool RemoveWebSocketService (string servicePath)
{
- if (servicePath.IsNullOrEmpty ())
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
{
- _logger.Error ("'servicePath' must not be null or empty.");
+ _logger.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return false;
}
@@ -576,7 +579,10 @@ namespace WebSocketSharp.Server
if (!_listening)
return;
- stop (0, null, true);
+ _listener.Close ();
+ _receiveRequestThread.Join (5 * 1000);
+ _serviceHosts.Stop ();
+ _listening = false;
}
///
@@ -594,13 +600,14 @@ namespace WebSocketSharp.Server
if (!_listening)
return;
- if (!code.IsCloseStatusCode ())
+ var msg = code.CheckIfValidCloseStatusCode ();
+ if (msg != null)
{
- _logger.Error ("Invalid status code for stop.\ncode: " + code);
+ _logger.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
}
- stop (code, reason, false);
+ stop (code, reason);
}
///
@@ -618,7 +625,7 @@ namespace WebSocketSharp.Server
if (!_listening)
return;
- stop ((ushort) code, reason, false);
+ stop ((ushort) code, reason);
}
#endregion
diff --git a/websocket-sharp/Server/IWebSocketServiceHost.cs b/websocket-sharp/Server/IWebSocketServiceHost.cs
index d7c1c00a..ad98dc00 100644
--- a/websocket-sharp/Server/IWebSocketServiceHost.cs
+++ b/websocket-sharp/Server/IWebSocketServiceHost.cs
@@ -79,22 +79,81 @@ namespace WebSocketSharp.Server
///
void Broadcast (string data);
+ ///
+ /// Sends Pings to all clients of the WebSocket service host.
+ ///
+ ///
+ /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
+ /// indicating whether the WebSocket service host received a Pong from each client in a time.
+ ///
+ Dictionary Broadping ();
+
///
/// Sends Pings with the specified to all clients of
/// the WebSocket service host.
///
///
/// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
- /// indicating whether the WebSocket service host received the Pong from each client in a time.
+ /// indicating whether the WebSocket service host received a Pong from each client in a time.
///
///
/// A that contains a message to send.
///
Dictionary Broadping (string message);
+ ///
+ /// Close the WebSocket session with the specified .
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ void CloseSession (string id);
+
+ ///
+ /// Close the WebSocket session with the specified ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ void CloseSession (ushort code, string reason, string id);
+
+ ///
+ /// Close the WebSocket session with the specified ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ void CloseSession (CloseStatusCode code, string reason, string id);
+
+ ///
+ /// Sends a Ping to the client associated with the specified .
+ ///
+ ///
+ /// true if the WebSocket service host receives a Pong from the client in a time;
+ /// otherwise, false.
+ ///
+ ///
+ /// A that contains a session ID that represents the destination for the Ping.
+ ///
+ bool PingTo (string id);
+
///
/// Sends a Ping with the specified to the client associated with
- /// the specified ID.
+ /// the specified .
///
///
/// true if the WebSocket service host receives a Pong from the client in a time;
@@ -104,12 +163,12 @@ namespace WebSocketSharp.Server
/// A that contains a message to send.
///
///
- /// A that contains an ID that represents the destination for the Ping.
+ /// A that contains a session ID that represents the destination for the Ping.
///
bool PingTo (string message, string id);
///
- /// Sends a binary data to the client associated with the specified ID.
+ /// Sends a binary data to the client associated with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -118,12 +177,12 @@ namespace WebSocketSharp.Server
/// An array of that contains a binary data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
bool SendTo (byte [] data, string id);
///
- /// Sends a text data to the client associated with the specified ID.
+ /// Sends a text data to the client associated with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -132,15 +191,10 @@ namespace WebSocketSharp.Server
/// A that contains a text data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
bool SendTo (string data, string id);
- ///
- /// Starts the WebSocket service host.
- ///
- void Start ();
-
///
/// Stops the WebSocket service host.
///
diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs
index f0e9d91f..2917ab04 100644
--- a/websocket-sharp/Server/WebSocketServer.cs
+++ b/websocket-sharp/Server/WebSocketServer.cs
@@ -199,10 +199,10 @@ namespace WebSocketSharp.Server
private void stop (ushort code, string reason)
{
var data = code.Append (reason);
- if (data.Length > 125)
+ var msg = data.CheckIfValidCloseData ();
+ if (msg != null)
{
- Log.Error (String.Format (
- "The payload length of a Close frame must be 125 bytes or less.\ncode: {0}\nreason: {1}", code, reason));
+ Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
@@ -223,9 +223,9 @@ namespace WebSocketSharp.Server
protected override void AcceptWebSocket (TcpListenerWebSocketContext context)
{
var websocket = context.WebSocket;
- var path = context.Path.UrlDecode ();
-
websocket.Log = Log;
+
+ var path = context.Path;
IWebSocketServiceHost host;
if (!_serviceHosts.TryGetServiceHost (path, out host))
{
@@ -246,6 +246,10 @@ namespace WebSocketSharp.Server
///
/// Adds the specified typed WebSocket service with the specified .
///
+ ///
+ /// This method converts to URL-decoded string and
+ /// removes '/' from tail end of .
+ ///
///
/// A that contains an absolute path to the WebSocket service.
///
@@ -255,10 +259,10 @@ namespace WebSocketSharp.Server
public void AddWebSocketService (string servicePath)
where T : WebSocketService, new ()
{
- string msg;
- if (!servicePath.IsValidAbsolutePath (out msg))
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
{
- Log.Error (msg);
+ Log.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return;
}
@@ -276,6 +280,10 @@ namespace WebSocketSharp.Server
///
/// Removes the WebSocket service with the specified .
///
+ ///
+ /// This method converts to URL-decoded string and
+ /// removes '/' from tail end of .
+ ///
///
/// true if the WebSocket service is successfully found and removed; otherwise, false.
///
@@ -284,9 +292,10 @@ namespace WebSocketSharp.Server
///
public bool RemoveWebSocketService (string servicePath)
{
- if (servicePath.IsNullOrEmpty ())
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
{
- Log.Error ("'servicePath' must not be null or empty.");
+ Log.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return false;
}
@@ -314,9 +323,10 @@ namespace WebSocketSharp.Server
///
public void Stop (ushort code, string reason)
{
- if (!code.IsCloseStatusCode ())
+ var msg = code.CheckIfValidCloseStatusCode ();
+ if (msg != null)
{
- Log.Error ("Invalid status code for stop.\ncode: " + code);
+ Log.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
}
diff --git a/websocket-sharp/Server/WebSocketServerBase.cs b/websocket-sharp/Server/WebSocketServerBase.cs
index 7b84faee..711347f7 100644
--- a/websocket-sharp/Server/WebSocketServerBase.cs
+++ b/websocket-sharp/Server/WebSocketServerBase.cs
@@ -117,7 +117,7 @@ namespace WebSocketSharp.Server
///
/// Initializes a new instance of the class
/// that listens for incoming connection attempts on the specified ,
- /// , and .
+ /// , and .
///
///
/// A that contains a local IP address.
@@ -125,7 +125,7 @@ namespace WebSocketSharp.Server
///
/// An that contains a port number.
///
- ///
+ ///
/// A that contains an absolute path.
///
///
@@ -133,14 +133,14 @@ namespace WebSocketSharp.Server
/// (true indicates providing a secure connection.)
///
///
- /// Either or is .
+ /// Either or is .
///
///
/// is 0 or less, or 65536 or greater.
///
///
///
- /// is invalid.
+ /// is invalid.
///
///
/// -or-
@@ -149,20 +149,20 @@ namespace WebSocketSharp.Server
/// Pair of and is invalid.
///
///
- protected WebSocketServerBase (IPAddress address, int port, string absPath, bool secure)
+ protected WebSocketServerBase (IPAddress address, int port, string servicePath, bool secure)
{
if (address == null)
throw new ArgumentNullException ("address");
- if (absPath == null)
- throw new ArgumentNullException ("absPath");
+ if (servicePath == null)
+ throw new ArgumentNullException ("servicePath");
if (!port.IsPortNumber ())
throw new ArgumentOutOfRangeException ("port", "Invalid port number: " + port);
- string msg;
- if (!absPath.IsValidAbsolutePath (out msg))
- throw new ArgumentException (msg, "absPath");
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
+ throw new ArgumentException (msg, "servicePath");
if ((port == 80 && secure) || (port == 443 && !secure))
throw new ArgumentException (String.Format (
@@ -170,7 +170,7 @@ namespace WebSocketSharp.Server
_address = address;
_port = port;
- _uri = absPath.ToUri ();
+ _uri = servicePath.ToUri ();
_secure = secure;
init ();
diff --git a/websocket-sharp/Server/WebSocketService.cs b/websocket-sharp/Server/WebSocketService.cs
index cd48680f..a380bf2a 100644
--- a/websocket-sharp/Server/WebSocketService.cs
+++ b/websocket-sharp/Server/WebSocketService.cs
@@ -37,7 +37,7 @@ using WebSocketSharp.Net.WebSockets;
namespace WebSocketSharp.Server
{
///
- /// Provides the basic functions of the WebSocket service.
+ /// Provides the basic functions of the WebSocket service managed by the WebSocket service host.
///
///
/// The WebSocketService class is an abstract class.
@@ -46,9 +46,9 @@ namespace WebSocketSharp.Server
{
#region Private Fields
+ private WebSocket _websocket;
private WebSocketContext _context;
private WebSocketServiceManager _sessions;
- private WebSocket _websocket;
#endregion
@@ -115,11 +115,10 @@ namespace WebSocketSharp.Server
}
///
- /// Gets the sessions to the instances.
+ /// Gets the collection of the WebSocket sessions managed by the WebSocket service host.
///
///
- /// A that contains the sessions to
- /// the instances.
+ /// A that contains a collection of the WebSocket sessions.
///
protected WebSocketServiceManager Sessions {
get {
@@ -134,10 +133,10 @@ namespace WebSocketSharp.Server
#region Public Properties
///
- /// Gets the ID of the current instance.
+ /// Gets the session ID of the current instance.
///
///
- /// A that contains an ID.
+ /// A that contains a session ID.
///
public string ID {
get; private set;
@@ -216,86 +215,6 @@ namespace WebSocketSharp.Server
#region Protected Methods
- ///
- /// Calls the method with the specified .
- ///
- ///
- /// A that contains an error message.
- ///
- protected virtual void Error (string message)
- {
- if (!message.IsNullOrEmpty ())
- OnError (new ErrorEventArgs (message));
- }
-
- ///
- /// Is called when the WebSocket connection has been closed.
- ///
- ///
- /// A that contains an event data associated with
- /// an inner event.
- ///
- protected virtual void OnClose (CloseEventArgs e)
- {
- }
-
- ///
- /// Is called when the inner or current
- /// gets an error.
- ///
- ///
- /// An that contains an event data associated with
- /// an inner event.
- ///
- protected virtual void OnError (ErrorEventArgs e)
- {
- }
-
- ///
- /// Is called when the inner receives a data frame.
- ///
- ///
- /// A that contains an event data associated with
- /// an inner event.
- ///
- protected virtual void OnMessage (MessageEventArgs e)
- {
- }
-
- ///
- /// Is called when the WebSocket connection has been established.
- ///
- protected virtual void OnOpen ()
- {
- }
-
- ///
- /// Validates the cookies used in the WebSocket connection request.
- ///
- ///
- /// This method is called when the inner validates
- /// the WebSocket connection request.
- ///
- ///
- /// true if the cookies is valid; otherwise, false.
- /// The default returns true.
- ///
- ///
- /// A that contains a collection of the HTTP Cookies
- /// to validate.
- ///
- ///
- /// A that receives the HTTP Cookies to send to the client.
- ///
- protected virtual bool ValidateCookies (CookieCollection request, CookieCollection response)
- {
- return true;
- }
-
- #endregion
-
- #region Public Methods
-
///
/// Broadcasts the specified array of to the clients of every
/// instances in the .
@@ -303,14 +222,14 @@ namespace WebSocketSharp.Server
///
/// An array of to broadcast.
///
- public virtual void Broadcast (byte [] data)
+ protected virtual void Broadcast (byte [] data)
{
if (!IsBound)
return;
- if (data == null)
+ var msg = data.CheckIfValidSendData ();
+ if (msg != null)
{
- var msg = "'data' must not be null.";
Log.Error (msg);
Error (msg);
@@ -327,14 +246,14 @@ namespace WebSocketSharp.Server
///
/// A to broadcast.
///
- public virtual void Broadcast (string data)
+ protected virtual void Broadcast (string data)
{
if (!IsBound)
return;
- if (data == null)
+ var msg = data.CheckIfValidSendData ();
+ if (msg != null)
{
- var msg = "'data' must not be null.";
Log.Error (msg);
Error (msg);
@@ -352,10 +271,10 @@ namespace WebSocketSharp.Server
/// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
/// indicating whether the each instance received a Pong in a time.
///
- public virtual Dictionary Broadping ()
+ protected virtual Dictionary Broadping ()
{
return IsBound
- ? _sessions.Broadping (String.Empty)
+ ? _sessions.Broadping ()
: null;
}
@@ -370,18 +289,14 @@ namespace WebSocketSharp.Server
///
/// A that contains a message to send.
///
- public virtual Dictionary Broadping (string message)
+ protected virtual Dictionary Broadping (string message)
{
if (!IsBound)
return null;
- if (message.IsNullOrEmpty ())
- return _sessions.Broadping (String.Empty);
-
- var len = Encoding.UTF8.GetBytes (message).Length;
- if (len > 125)
+ var msg = message.CheckIfValidPingMessage ();
+ if (msg != null)
{
- var msg = "The payload length of a Ping frame must be 125 bytes or less.";
Log.Error (msg);
Error (msg);
@@ -392,56 +307,89 @@ namespace WebSocketSharp.Server
}
///
- /// Sends a Ping to the client of the current instance.
+ /// Calls the method with the specified .
///
- ///
- /// true if the current instance receives a Pong in a time;
- /// otherwise, false.
- ///
- public virtual bool Ping ()
+ ///
+ /// A that contains an error message.
+ ///
+ protected virtual void Error (string message)
{
- return IsBound
- ? _websocket.Ping ()
- : false;
+ if (!message.IsNullOrEmpty ())
+ OnError (new ErrorEventArgs (message));
}
///
- /// Sends a Ping with the specified to the client of
- /// the current instance.
+ /// Is called when the WebSocket connection has been closed.
///
- ///
- /// true if the current instance receives a Pong in a time;
- /// otherwise, false.
- ///
- ///
- /// A that contains a message to send.
+ ///
+ /// A that contains an event data associated with
+ /// an inner event.
///
- public virtual bool Ping (string message)
+ protected virtual void OnClose (CloseEventArgs e)
+ {
+ }
+
+ ///
+ /// Is called when the inner or current
+ /// gets an error.
+ ///
+ ///
+ /// An that contains an event data associated with
+ /// an inner event.
+ ///
+ protected virtual void OnError (ErrorEventArgs e)
+ {
+ }
+
+ ///
+ /// Is called when the inner receives a data frame.
+ ///
+ ///
+ /// A that contains an event data associated with
+ /// an inner event.
+ ///
+ protected virtual void OnMessage (MessageEventArgs e)
+ {
+ }
+
+ ///
+ /// Is called when the WebSocket connection has been established.
+ ///
+ protected virtual void OnOpen ()
{
- return IsBound
- ? _websocket.Ping (message)
- : false;
}
///
/// Sends a Ping to the client of the instance
- /// with the specified ID.
+ /// with the specified .
///
///
/// true if the instance with receives
/// a Pong in a time; otherwise, false.
///
///
- /// A that contains an ID that represents the destination for the Ping.
+ /// A that contains a session ID that represents the destination for the Ping.
///
- public virtual bool PingTo (string id)
+ protected virtual bool PingTo (string id)
{
- return PingTo (String.Empty, id);
+ if (!IsBound)
+ return false;
+
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
+ {
+ Log.Error (msg);
+ Error (msg);
+
+ return false;
+ }
+
+ return _sessions.PingTo (id);
}
///
/// Sends a Ping with the specified to the client of
- /// the instance with the specified ID.
+ /// the instance with the specified .
///
///
/// true if the instance with receives
@@ -451,16 +399,16 @@ namespace WebSocketSharp.Server
/// A that contains a message to send.
///
///
- /// A that contains an ID that represents the destination for the Ping.
+ /// A that contains a session ID that represents the destination for the Ping.
///
- public virtual bool PingTo (string message, string id)
+ protected virtual bool PingTo (string message, string id)
{
if (!IsBound)
return false;
- if (id.IsNullOrEmpty ())
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
{
- var msg = "'id' must not be null or empty.";
Log.Error (msg);
Error (msg);
@@ -470,33 +418,9 @@ namespace WebSocketSharp.Server
return _sessions.PingTo (message, id);
}
- ///
- /// Sends a binary data to the client of the current instance.
- ///
- ///
- /// An array of that contains a binary data to send.
- ///
- public virtual void Send (byte [] data)
- {
- if (IsBound)
- _websocket.Send (data);
- }
-
- ///
- /// Sends a text data to the client of the current instance.
- ///
- ///
- /// A that contains a text data to send.
- ///
- public virtual void Send (string data)
- {
- if (IsBound)
- _websocket.Send (data);
- }
-
///
/// Sends a binary data to the client of the instance
- /// with the specified ID.
+ /// with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -505,19 +429,14 @@ namespace WebSocketSharp.Server
/// An array of that contains a binary data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
- public virtual bool SendTo (byte [] data, string id)
+ protected virtual bool SendTo (byte [] data, string id)
{
if (!IsBound)
return false;
- var msg = data == null
- ? "'data' must not be null."
- : id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : null;
-
+ var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
@@ -531,7 +450,7 @@ namespace WebSocketSharp.Server
///
/// Sends a text data to the client of the instance
- /// with the specified ID.
+ /// with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -540,19 +459,14 @@ namespace WebSocketSharp.Server
/// A that contains a text data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
- public virtual bool SendTo (string data, string id)
+ protected virtual bool SendTo (string data, string id)
{
if (!IsBound)
return false;
- var msg = data == null
- ? "'data' must not be null."
- : id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : null;
-
+ var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
@@ -564,6 +478,89 @@ namespace WebSocketSharp.Server
return _sessions.SendTo (data, id);
}
+ ///
+ /// Validates the cookies used in the WebSocket connection request.
+ ///
+ ///
+ /// This method is called when the inner validates
+ /// the WebSocket connection request.
+ ///
+ ///
+ /// true if the cookies is valid; otherwise, false.
+ /// The default returns true.
+ ///
+ ///
+ /// A that contains a collection of the HTTP Cookies
+ /// to validate.
+ ///
+ ///
+ /// A that receives the HTTP Cookies to send to the client.
+ ///
+ protected virtual bool ValidateCookies (CookieCollection request, CookieCollection response)
+ {
+ return true;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ ///
+ /// Sends a Ping to the client of the current instance.
+ ///
+ ///
+ /// true if the current instance receives a Pong in a time;
+ /// otherwise, false.
+ ///
+ public virtual bool Ping ()
+ {
+ return IsBound
+ ? _websocket.Ping ()
+ : false;
+ }
+
+ ///
+ /// Sends a Ping with the specified to the client of
+ /// the current instance.
+ ///
+ ///
+ /// true if the current instance receives a Pong in a time;
+ /// otherwise, false.
+ ///
+ ///
+ /// A that contains a message to send.
+ ///
+ public virtual bool Ping (string message)
+ {
+ return IsBound
+ ? _websocket.Ping (message)
+ : false;
+ }
+
+ ///
+ /// Sends a binary data to the client of the current instance.
+ ///
+ ///
+ /// An array of that contains a binary data to send.
+ ///
+ public virtual void Send (byte [] data)
+ {
+ if (IsBound)
+ _websocket.Send (data);
+ }
+
+ ///
+ /// Sends a text data to the client of the current instance.
+ ///
+ ///
+ /// A that contains a text data to send.
+ ///
+ public virtual void Send (string data)
+ {
+ if (IsBound)
+ _websocket.Send (data);
+ }
+
///
/// Starts the current instance.
///
diff --git a/websocket-sharp/Server/WebSocketServiceHost.cs b/websocket-sharp/Server/WebSocketServiceHost.cs
index 8c293fe1..818874c2 100644
--- a/websocket-sharp/Server/WebSocketServiceHost.cs
+++ b/websocket-sharp/Server/WebSocketServiceHost.cs
@@ -52,6 +52,7 @@ namespace WebSocketSharp.Server
{
#region Private Fields
+ private string _servicePath;
private WebSocketServiceManager _sessions;
#endregion
@@ -111,43 +112,43 @@ namespace WebSocketSharp.Server
///
/// Initializes a new instance of the WebSocketServiceHost<T> class that listens for
- /// incoming connection attempts on the specified and .
+ /// incoming connection attempts on the specified and .
///
///
/// An that contains a port number.
///
- ///
+ ///
/// A that contains an absolute path.
///
- public WebSocketServiceHost (int port, string absPath)
- : this (System.Net.IPAddress.Any, port, absPath)
+ public WebSocketServiceHost (int port, string servicePath)
+ : this (System.Net.IPAddress.Any, port, servicePath)
{
}
///
/// Initializes a new instance of the WebSocketServiceHost<T> class that listens for
- /// incoming connection attempts on the specified ,
+ /// incoming connection attempts on the specified ,
/// and .
///
///
/// An that contains a port number.
///
- ///
+ ///
/// A that contains an absolute path.
///
///
/// A that indicates providing a secure connection or not.
/// (true indicates providing a secure connection.)
///
- public WebSocketServiceHost (int port, string absPath, bool secure)
- : this (System.Net.IPAddress.Any, port, absPath, secure)
+ public WebSocketServiceHost (int port, string servicePath, bool secure)
+ : this (System.Net.IPAddress.Any, port, servicePath, secure)
{
}
///
/// Initializes a new instance of the WebSocketServiceHost<T> class that listens for
/// incoming connection attempts on the specified ,
- /// and .
+ /// and .
///
///
/// A that contains a local IP address.
@@ -155,18 +156,18 @@ namespace WebSocketSharp.Server
///
/// An that contains a port number.
///
- ///
+ ///
/// A that contains an absolute path.
///
- public WebSocketServiceHost (System.Net.IPAddress address, int port, string absPath)
- : this (address, port, absPath, port == 443 ? true : false)
+ public WebSocketServiceHost (System.Net.IPAddress address, int port, string servicePath)
+ : this (address, port, servicePath, port == 443 ? true : false)
{
}
///
/// Initializes a new instance of the WebSocketServiceHost<T> class that listens for
/// incoming connection attempts on the specified , ,
- /// and .
+ /// and .
///
///
/// A that contains a local IP address.
@@ -174,15 +175,15 @@ namespace WebSocketSharp.Server
///
/// An that contains a port number.
///
- ///
+ ///
/// A that contains an absolute path.
///
///
/// A that indicates providing a secure connection or not.
/// (true indicates providing a secure connection.)
///
- public WebSocketServiceHost (System.Net.IPAddress address, int port, string absPath, bool secure)
- : base (address, port, absPath, secure)
+ public WebSocketServiceHost (System.Net.IPAddress address, int port, string servicePath, bool secure)
+ : base (address, port, servicePath, secure)
{
_sessions = new WebSocketServiceManager (Log);
}
@@ -208,8 +209,8 @@ namespace WebSocketSharp.Server
/// the inactive instances periodically.
///
///
- /// true if the WebSocket service host cleans up the inactive WebSocket service instances every 60 seconds;
- /// otherwise, false. The default value is true.
+ /// true if the WebSocket service host cleans up the inactive WebSocket service instances
+ /// every 60 seconds; otherwise, false. The default value is true.
///
public bool KeepClean {
get {
@@ -221,6 +222,33 @@ namespace WebSocketSharp.Server
}
}
+ ///
+ /// Gets the collection of the WebSocket sessions managed by the WebSocket service host.
+ ///
+ ///
+ /// A that contains a collection of the WebSocket sessions.
+ ///
+ public WebSocketServiceManager Sessions {
+ get {
+ return _sessions;
+ }
+ }
+
+ ///
+ /// Gets the path to the WebSocket service that the WebSocket service host provides.
+ ///
+ ///
+ /// A that contains an absolute path to the WebSocket service.
+ ///
+ public string ServicePath {
+ get {
+ if (_servicePath == null)
+ _servicePath = HttpUtility.UrlDecode (BaseUri.GetAbsolutePath ()).TrimEndSlash ();
+
+ return _servicePath;
+ }
+ }
+
///
/// Gets the WebSocket URL on which to listen for incoming connection attempts.
///
@@ -244,10 +272,10 @@ namespace WebSocketSharp.Server
private void stop (ushort code, string reason)
{
var data = code.Append (reason);
- if (data.Length > 125)
+ var msg = data.CheckIfValidCloseData ();
+ if (msg != null)
{
- Log.Error (String.Format (
- "The payload length of a Close frame must be 125 bytes or less.\ncode: {0}\nreason: {1}", code, reason));
+ Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
@@ -268,17 +296,17 @@ namespace WebSocketSharp.Server
protected override void AcceptWebSocket (TcpListenerWebSocketContext context)
{
var websocket = context.WebSocket;
- var path = context.Path.UrlDecode ();
-
websocket.Log = Log;
- if (path != Uri.GetAbsolutePath ().UrlDecode ())
+
+ var path = HttpUtility.UrlDecode (context.Path).TrimEndSlash ();
+ if (path != ServicePath)
{
websocket.Close (HttpStatusCode.NotImplemented);
return;
}
- if (Uri.IsAbsoluteUri)
- websocket.Url = Uri;
+ if (BaseUri.IsAbsoluteUri)
+ websocket.Url = BaseUri;
((IWebSocketServiceHost) this).BindWebSocket (context);
}
@@ -295,9 +323,10 @@ namespace WebSocketSharp.Server
///
public void Broadcast (byte [] data)
{
- if (data == null)
+ var msg = data.CheckIfValidSendData ();
+ if (msg != null)
{
- Log.Error ("'data' must not be null.");
+ Log.Error (msg);
return;
}
@@ -312,58 +341,160 @@ namespace WebSocketSharp.Server
///
public void Broadcast (string data)
{
- if (data == null)
+ var msg = data.CheckIfValidSendData ();
+ if (msg != null)
{
- Log.Error ("'data' must not be null.");
+ Log.Error (msg);
return;
}
_sessions.Broadcast (data);
}
+ ///
+ /// Sends Pings to all clients.
+ ///
+ ///
+ /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
+ /// indicating whether the WebSocket service host received a Pong from each client in a time.
+ ///
+ public Dictionary Broadping ()
+ {
+ return _sessions.Broadping ();
+ }
+
///
/// Sends Pings with the specified to all clients.
///
///
/// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
- /// indicating whether the service host received the Pong from each client in a time.
+ /// indicating whether the WebSocket service host received a Pong from each client in a time.
///
///
/// A that contains a message to send.
///
public Dictionary Broadping (string message)
{
- if (message.IsNullOrEmpty ())
- return _sessions.Broadping (String.Empty);
-
- var len = Encoding.UTF8.GetBytes (message).Length;
- if (len > 125)
+ var msg = message.CheckIfValidPingMessage ();
+ if (msg != null)
{
- Log.Error ("The payload length of a Ping frame must be 125 bytes or less.");
+ Log.Error (msg);
return null;
}
return _sessions.Broadping (message);
}
+ ///
+ /// Close the WebSocket session with the specified .
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ public void CloseSession (string id)
+ {
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
+ {
+ Log.Error (msg);
+ return;
+ }
+
+ _sessions.StopServiceInstance (id);
+ }
+
+ ///
+ /// Close the WebSocket session with the specified ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ public void CloseSession (ushort code, string reason, string id)
+ {
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
+ {
+ Log.Error (msg);
+ return;
+ }
+
+ _sessions.StopServiceInstance (code, reason, id);
+ }
+
+ ///
+ /// Close the WebSocket session with the specified ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ public void CloseSession (CloseStatusCode code, string reason, string id)
+ {
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
+ {
+ Log.Error (msg);
+ return;
+ }
+
+ _sessions.StopServiceInstance (code, reason, id);
+ }
+
+ ///
+ /// Sends a Ping to the client associated with the specified .
+ ///
+ ///
+ /// true if the WebSocket service host receives a Pong from the client in a time;
+ /// otherwise, false.
+ ///
+ ///
+ /// A that contains a session ID that represents the destination for the Ping.
+ ///
+ public bool PingTo (string id)
+ {
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
+ {
+ Log.Error (msg);
+ return false;
+ }
+
+ return _sessions.PingTo (id);
+ }
+
///
/// Sends a Ping with the specified to the client associated with
- /// the specified ID.
+ /// the specified .
///
///
- /// true if the service host receives a Pong from the client in a time; otherwise, false.
+ /// true if the WebSocket service host receives a Pong from the client in a time;
+ /// otherwise, false.
///
///
/// A that contains a message to send.
///
///
- /// A that contains an ID that represents the destination for the Ping.
+ /// A that contains a session ID that represents the destination for the Ping.
///
public bool PingTo (string message, string id)
{
- if (id.IsNullOrEmpty ())
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
{
- Log.Error ("'id' must not be null or empty.");
+ Log.Error (msg);
return false;
}
@@ -371,7 +502,7 @@ namespace WebSocketSharp.Server
}
///
- /// Sends a binary data to the client associated with the specified ID.
+ /// Sends a binary data to the client associated with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -380,16 +511,11 @@ namespace WebSocketSharp.Server
/// An array of that contains a binary data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
public bool SendTo (byte [] data, string id)
{
- var msg = data == null
- ? "'data' must not be null."
- : id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : null;
-
+ var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
@@ -400,7 +526,7 @@ namespace WebSocketSharp.Server
}
///
- /// Sends a text data to the client associated with the specified ID.
+ /// Sends a text data to the client associated with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -409,16 +535,11 @@ namespace WebSocketSharp.Server
/// A that contains a text data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
public bool SendTo (string data, string id)
{
- var msg = data == null
- ? "'data' must not be null."
- : id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : null;
-
+ var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
@@ -449,9 +570,10 @@ namespace WebSocketSharp.Server
///
public void Stop (ushort code, string reason)
{
- if (!code.IsCloseStatusCode ())
+ var msg = code.CheckIfValidCloseStatusCode ();
+ if (msg != null)
{
- Log.Error ("Invalid status code for stop.\ncode: " + code);
+ Log.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
}
@@ -527,18 +649,81 @@ namespace WebSocketSharp.Server
return _sessions.Broadping (message);
}
+ ///
+ /// Close the WebSocket session with the specified .
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ void IWebSocketServiceHost.CloseSession (string id)
+ {
+ _sessions.StopServiceInstance (id);
+ }
+
+ ///
+ /// Close the WebSocket session with the specified ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ void IWebSocketServiceHost.CloseSession (ushort code, string reason, string id)
+ {
+ _sessions.StopServiceInstance (code, reason, id);
+ }
+
+ ///
+ /// Close the WebSocket session with the specified ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ void IWebSocketServiceHost.CloseSession (CloseStatusCode code, string reason, string id)
+ {
+ _sessions.StopServiceInstance (code, reason, id);
+ }
+
+ ///
+ /// Sends a Ping to the client associated with the specified .
+ ///
+ ///
+ /// true if the WebSocket service host receives a Pong from the client in a time;
+ /// otherwise, false.
+ ///
+ ///
+ /// A that contains a session ID that represents the destination for the Ping.
+ ///
+ bool IWebSocketServiceHost.PingTo (string id)
+ {
+ return _sessions.PingTo (id);
+ }
+
///
/// Sends a Ping with the specified to the client associated with
- /// the specified ID.
+ /// the specified .
///
///
- /// true if the service host receives a Pong from the client in a time; otherwise, false.
+ /// true if the WebSocket service host receives a Pong from the client in a time;
+ /// otherwise, false.
///
///
/// A that contains a message to send.
///
///
- /// A that contains an ID that represents the destination for the Ping.
+ /// A that contains a session ID that represents the destination for the Ping.
///
bool IWebSocketServiceHost.PingTo (string message, string id)
{
@@ -546,7 +731,7 @@ namespace WebSocketSharp.Server
}
///
- /// Sends a binary data to the client associated with the specified ID.
+ /// Sends a binary data to the client associated with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -555,7 +740,7 @@ namespace WebSocketSharp.Server
/// An array of that contains a binary data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
bool IWebSocketServiceHost.SendTo (byte [] data, string id)
{
@@ -563,7 +748,7 @@ namespace WebSocketSharp.Server
}
///
- /// Sends a text data to the client associated with the specified ID.
+ /// Sends a text data to the client associated with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -572,7 +757,7 @@ namespace WebSocketSharp.Server
/// A that contains a text data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
bool IWebSocketServiceHost.SendTo (string data, string id)
{
diff --git a/websocket-sharp/Server/WebSocketServiceHostManager.cs b/websocket-sharp/Server/WebSocketServiceHostManager.cs
index 0bd1fcf0..2bc238ff 100644
--- a/websocket-sharp/Server/WebSocketServiceHostManager.cs
+++ b/websocket-sharp/Server/WebSocketServiceHostManager.cs
@@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using WebSocketSharp.Net;
namespace WebSocketSharp.Server
{
@@ -63,6 +64,37 @@ namespace WebSocketSharp.Server
#endregion
+ #region Internal Properties
+
+ internal bool KeepClean {
+ get {
+ return _keepClean;
+ }
+
+ set {
+ lock (_sync)
+ {
+ if (_keepClean ^ value)
+ {
+ _keepClean = value;
+ foreach (var host in _serviceHosts.Values)
+ host.KeepClean = value;
+ }
+ }
+ }
+ }
+
+ internal IEnumerable ServiceHosts {
+ get {
+ lock (_sync)
+ {
+ return _serviceHosts.Values;
+ }
+ }
+ }
+
+ #endregion
+
#region Public Properties
///
@@ -87,7 +119,7 @@ namespace WebSocketSharp.Server
///
/// An that contains the number of the WebSocket services.
///
- public int ServiceCount {
+ public int Count {
get {
lock (_sync)
{
@@ -113,37 +145,6 @@ namespace WebSocketSharp.Server
#endregion
- #region Internal Properties
-
- internal bool KeepClean {
- get {
- return _keepClean;
- }
-
- set {
- lock (_sync)
- {
- if (_keepClean ^ value)
- {
- _keepClean = value;
- foreach (var host in _serviceHosts.Values)
- host.KeepClean = value;
- }
- }
- }
- }
-
- internal IEnumerable ServiceHosts {
- get {
- lock (_sync)
- {
- return _serviceHosts.Values;
- }
- }
- }
-
- #endregion
-
#region Private Methods
private Dictionary copy ()
@@ -160,6 +161,7 @@ namespace WebSocketSharp.Server
internal void Add (string servicePath, IWebSocketServiceHost serviceHost)
{
+ servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash ();
lock (_sync)
{
IWebSocketServiceHost host;
@@ -170,12 +172,14 @@ namespace WebSocketSharp.Server
return;
}
- _serviceHosts.Add (servicePath.UrlDecode (), serviceHost);
+ _serviceHosts.Add (servicePath, serviceHost);
}
}
internal bool Remove (string servicePath)
{
+ servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash ();
+
IWebSocketServiceHost host;
lock (_sync)
{
@@ -217,6 +221,7 @@ namespace WebSocketSharp.Server
internal bool TryGetServiceHost (string servicePath, out IWebSocketServiceHost serviceHost)
{
+ servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash ();
lock (_sync)
{
return _serviceHosts.TryGetValue (servicePath, out serviceHost);
@@ -228,16 +233,18 @@ namespace WebSocketSharp.Server
#region Public Methods
///
- /// Broadcasts the specified array of to all clients of the WebSocket services.
+ /// Broadcasts the specified array of to all clients of the WebSocket services
+ /// managed by the .
///
///
/// An array of to broadcast.
///
public void Broadcast (byte [] data)
{
- if (data == null)
+ var msg = data.CheckIfValidSendData ();
+ if (msg != null)
{
- _logger.Error ("'data' must not be null.");
+ _logger.Error (msg);
return;
}
@@ -246,16 +253,18 @@ namespace WebSocketSharp.Server
}
///
- /// Broadcasts the specified to all clients of the WebSocket services.
+ /// Broadcasts the specified to all clients of the WebSocket services
+ /// managed by the .
///
///
/// A to broadcast.
///
public void Broadcast (string data)
{
- if (data == null)
+ var msg = data.CheckIfValidSendData ();
+ if (msg != null)
{
- _logger.Error ("'data' must not be null.");
+ _logger.Error (msg);
return;
}
@@ -278,12 +287,7 @@ namespace WebSocketSharp.Server
///
public bool BroadcastTo (byte [] data, string servicePath)
{
- var msg = data == null
- ? "'data' must not be null."
- : servicePath.IsNullOrEmpty ()
- ? "'servicePath' must not be null or empty."
- : null;
-
+ var msg = data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
@@ -316,12 +320,7 @@ namespace WebSocketSharp.Server
///
public bool BroadcastTo (string data, string servicePath)
{
- var msg = data == null
- ? "'data' must not be null."
- : servicePath.IsNullOrEmpty ()
- ? "'servicePath' must not be null or empty."
- : null;
-
+ var msg = data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
@@ -340,26 +339,41 @@ namespace WebSocketSharp.Server
}
///
- /// Sends Pings with the specified to all clients of the WebSocket services.
+ /// Sends Pings to all clients of the WebSocket services managed by the .
+ ///
+ ///
+ /// A Dictionary<string, Dictionary<string, bool>> that contains the collection of
+ /// service paths and pairs of session ID and value indicating whether each WebSocket service
+ /// received a Pong from each client in a time.
+ ///
+ public Dictionary> Broadping ()
+ {
+ var result = new Dictionary> ();
+ foreach (var service in copy ())
+ result.Add (service.Key, service.Value.Broadping ());
+
+ return result;
+ }
+
+ ///
+ /// Sends Pings with the specified to all clients of the WebSocket services
+ /// managed by the .
///
///
/// A Dictionary<string, Dictionary<string, bool>> that contains the collection of
/// service paths and pairs of session ID and value indicating whether each WebSocket service
- /// received the Pong from each client in a time.
+ /// received a Pong from each client in a time.
///
///
/// A that contains a message to send.
///
public Dictionary> Broadping (string message)
{
- if (!message.IsNullOrEmpty ())
+ var msg = message.CheckIfValidPingMessage ();
+ if (msg != null)
{
- var len = Encoding.UTF8.GetBytes (message).Length;
- if (len > 125)
- {
- _logger.Error ("The payload length of a Ping frame must be 125 bytes or less.");
- return null;
- }
+ _logger.Error (msg);
+ return null;
}
var result = new Dictionary> ();
@@ -369,13 +383,43 @@ namespace WebSocketSharp.Server
return result;
}
+ ///
+ /// Sends Pings to all clients of the WebSocket service with the specified .
+ ///
+ ///
+ /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
+ /// indicating whether the WebSocket service received a Pong from each client in a time.
+ /// If the WebSocket service is not found, returns .
+ ///
+ ///
+ /// A that contains an absolute path to the WebSocket service to find.
+ ///
+ public Dictionary BroadpingTo (string servicePath)
+ {
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
+ {
+ _logger.Error (msg);
+ return null;
+ }
+
+ IWebSocketServiceHost host;
+ if (!TryGetServiceHost (servicePath, out host))
+ {
+ _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
+ return null;
+ }
+
+ return host.Broadping ();
+ }
+
///
/// Sends Pings with the specified to all clients of the WebSocket service
/// with the specified .
///
///
/// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
- /// indicating whether the WebSocket service received the Pong from each client in a time.
+ /// indicating whether the WebSocket service received a Pong from each client in a time.
/// If the WebSocket service is not found, returns .
///
///
@@ -386,15 +430,7 @@ namespace WebSocketSharp.Server
///
public Dictionary BroadpingTo (string message, string servicePath)
{
- if (message == null)
- message = String.Empty;
-
- var msg = Encoding.UTF8.GetBytes (message).Length > 125
- ? "The payload length of a Ping frame must be 125 bytes or less."
- : servicePath.IsNullOrEmpty ()
- ? "'servicePath' must not be null or empty."
- : null;
-
+ var msg = message.CheckIfValidPingMessage () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
@@ -411,21 +447,121 @@ namespace WebSocketSharp.Server
return host.Broadping (message);
}
+ ///
+ /// Close the WebSocket session with the specified and
+ /// .
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ ///
+ /// A that contains an absolute path to the WebSocket service to find.
+ ///
+ public void CloseSession (string id, string servicePath)
+ {
+ var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
+ if (msg != null)
+ {
+ _logger.Error (msg);
+ return;
+ }
+
+ IWebSocketServiceHost host;
+ if (!TryGetServiceHost (servicePath, out host))
+ {
+ _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
+ return;
+ }
+
+ host.CloseSession (id);
+ }
+
+ ///
+ /// Close the WebSocket session with the specified , ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ ///
+ /// A that contains an absolute path to the WebSocket service to find.
+ ///
+ public void CloseSession (ushort code, string reason, string id, string servicePath)
+ {
+ var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
+ if (msg != null)
+ {
+ _logger.Error (msg);
+ return;
+ }
+
+ IWebSocketServiceHost host;
+ if (!TryGetServiceHost (servicePath, out host))
+ {
+ _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
+ return;
+ }
+
+ host.CloseSession (code, reason, id);
+ }
+
+ ///
+ /// Close the WebSocket session with the specified , ,
+ /// and .
+ ///
+ ///
+ /// A that contains a status code indicating the reason for closure.
+ ///
+ ///
+ /// A that contains the reason for closure.
+ ///
+ ///
+ /// A that contains a session ID to find.
+ ///
+ ///
+ /// A that contains an absolute path to the WebSocket service to find.
+ ///
+ public void CloseSession (CloseStatusCode code, string reason, string id, string servicePath)
+ {
+ var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
+ if (msg != null)
+ {
+ _logger.Error (msg);
+ return;
+ }
+
+ IWebSocketServiceHost host;
+ if (!TryGetServiceHost (servicePath, out host))
+ {
+ _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
+ return;
+ }
+
+ host.CloseSession (code, reason, id);
+ }
+
///
/// Gets the connection count to the WebSocket service with the specified .
///
///
- /// An that contains the connection count if the WebSocket service is successfully found;
- /// otherwise, -1.
+ /// An that contains the connection count if the WebSocket service is successfully
+ /// found; otherwise, -1.
///
///
/// A that contains an absolute path to the WebSocket service to find.
///
public int GetConnectionCount (string servicePath)
{
- if (servicePath.IsNullOrEmpty ())
+ var msg = servicePath.CheckIfValidServicePath ();
+ if (msg != null)
{
- _logger.Error ("'servicePath' must not be null or empty.");
+ _logger.Error (msg);
return -1;
}
@@ -439,6 +575,39 @@ namespace WebSocketSharp.Server
return host.ConnectionCount;
}
+ ///
+ /// Sends a Ping to the client associated with the specified and
+ /// .
+ ///
+ ///
+ /// true if the WebSocket service with receives a Pong
+ /// from the client in a time; otherwise, false.
+ ///
+ ///
+ /// A that contains a session ID that represents the destination for the Ping.
+ ///
+ ///
+ /// A that contains an absolute path to the WebSocket service to find.
+ ///
+ public bool PingTo (string id, string servicePath)
+ {
+ var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
+ if (msg != null)
+ {
+ _logger.Error (msg);
+ return false;
+ }
+
+ IWebSocketServiceHost host;
+ if (!TryGetServiceHost (servicePath, out host))
+ {
+ _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
+ return false;
+ }
+
+ return host.PingTo (id);
+ }
+
///
/// Sends a Ping with the specified to the client associated with
/// the specified and .
@@ -451,18 +620,15 @@ namespace WebSocketSharp.Server
/// A that contains a message to send.
///
///
- /// A that contains an ID that represents the destination for the Ping.
+ /// A that contains a session ID that represents the destination for the Ping.
///
///
/// A that contains an absolute path to the WebSocket service to find.
///
public bool PingTo (string message, string id, string servicePath)
{
- var msg = id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : servicePath.IsNullOrEmpty ()
- ? "'servicePath' must not be null or empty."
- : null;
+ var msg = (message.CheckIfValidPingMessage () ?? id.CheckIfValidSessionID ()) ??
+ servicePath.CheckIfValidServicePath ();
if (msg != null)
{
@@ -491,20 +657,15 @@ namespace WebSocketSharp.Server
/// An array of that contains a binary data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
///
/// A that contains an absolute path to the WebSocket service to find.
///
public bool SendTo (byte [] data, string id, string servicePath)
{
- var msg = data == null
- ? "'data' must not be null."
- : id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : servicePath.IsNullOrEmpty ()
- ? "'servicePath' must not be null or empty."
- : null;
+ var msg = (data.CheckIfValidSendData () ?? id.CheckIfValidSessionID ()) ??
+ servicePath.CheckIfValidServicePath ();
if (msg != null)
{
@@ -533,20 +694,15 @@ namespace WebSocketSharp.Server
/// A that contains a text data to send.
///
///
- /// A that contains an ID that represents the destination for the data.
+ /// A that contains a session ID that represents the destination for the data.
///
///
/// A that contains an absolute path to the WebSocket service to find.
///
public bool SendTo (string data, string id, string servicePath)
{
- var msg = data == null
- ? "'data' must not be null."
- : id.IsNullOrEmpty ()
- ? "'id' must not be null or empty."
- : servicePath.IsNullOrEmpty ()
- ? "'servicePath' must not be null or empty."
- : null;
+ var msg = (data.CheckIfValidSendData () ?? id.CheckIfValidSessionID ()) ??
+ servicePath.CheckIfValidServicePath ();
if (msg != null)
{
diff --git a/websocket-sharp/Server/WebSocketServiceManager.cs b/websocket-sharp/Server/WebSocketServiceManager.cs
index a49078a5..a0f7892d 100644
--- a/websocket-sharp/Server/WebSocketServiceManager.cs
+++ b/websocket-sharp/Server/WebSocketServiceManager.cs
@@ -84,7 +84,7 @@ namespace WebSocketSharp.Server
///
public IEnumerable ActiveIDs {
get {
- return from result in Broadping (String.Empty)
+ return from result in Broadping ()
where result.Value
select result.Key;
}
@@ -134,14 +134,14 @@ namespace WebSocketSharp.Server
///
public IEnumerable InactiveIDs {
get {
- return from result in Broadping (String.Empty)
+ return from result in Broadping ()
where !result.Value
select result.Key;
}
}
///
- /// Gets the instance with the specified ID
+ /// Gets the instance with the specified
/// from the .
///
///
@@ -153,9 +153,10 @@ namespace WebSocketSharp.Server
///
public WebSocketService this [string id] {
get {
- if (id.IsNullOrEmpty ())
+ var msg = id.CheckIfValidSessionID ();
+ if (msg != null)
{
- _logger.Error ("'id' must not be null or empty.");
+ _logger.Error (msg);
return null;
}
@@ -289,23 +290,6 @@ namespace WebSocketSharp.Server
_sweepTimer.Start ();
}
- private void stop (ushort code, string reason, bool ignoreArgs)
- {
- stopSweepTimer ();
- lock (_sync)
- {
- if (_stopped)
- return;
-
- _stopped = true;
- foreach (var service in copy ().Values)
- if (ignoreArgs)
- service.Stop ();
- else
- service.Stop (code, reason);
- }
- }
-
private void stopSweepTimer ()
{
if (_sweepTimer.Enabled)
@@ -331,8 +315,8 @@ namespace WebSocketSharp.Server
}
///
- /// Broadcasts the specified array of to the clients of every
- /// instances managed by the .
+ /// Broadcasts the specified array of to the clients of every
+ /// instances managed by the .
///
///
/// An array of to broadcast.
@@ -346,8 +330,8 @@ namespace WebSocketSharp.Server
}
///
- /// Broadcasts the specified to the clients of every
- /// instances managed by the .
+ /// Broadcasts the specified to the clients of every
+ /// instances managed by the .
///
///
/// A to broadcast.
@@ -361,12 +345,29 @@ namespace WebSocketSharp.Server
}
///
- /// Sends Pings with the specified to the clients of every
- /// instances managed by the .
+ /// Sends Pings to the clients of every instances managed by
+ /// the .
+ ///
+ ///
+ /// A Dictionary<string, bool> that contains the collection of pairs of ID and value indicating
+ /// whether each instance received a Pong from the client in a time.
+ ///
+ internal Dictionary Broadping ()
+ {
+ var result = new Dictionary ();
+ foreach (var session in copy ())
+ result.Add (session.Key, session.Value.Ping ());
+
+ return result;
+ }
+
+ ///
+ /// Sends Pings with the specified to the clients of every
+ /// instances managed by the .
///
///
- /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value
- /// indicating whether the each instance received a Pong in a time.
+ /// A Dictionary<string, bool> that contains the collection of pairs of ID and value indicating
+ /// whether each instance received a Pong from the client in a time.
///
///
/// A that contains a message to send.
@@ -381,12 +382,36 @@ namespace WebSocketSharp.Server
}
///
- /// Sends a Ping with the specified to the client of
- /// the instance with the specified ID.
+ /// Sends a Ping to the client of the instance
+ /// with the specified .
///
///
- /// true if the instance with receives
- /// a Pong in a time; otherwise, false.
+ /// true if the instance receives a Pong from the client
+ /// in a time; otherwise, false.
+ ///
+ ///
+ /// A that contains an ID that represents the destination for the Ping.
+ ///
+ internal bool PingTo (string id)
+ {
+ WebSocketService service;
+ if (!TryGetServiceInstance (id, out service))
+ {
+ _logger.Error (
+ "The WebSocket service instance with the specified ID not found.\nID: " + id);
+ return false;
+ }
+
+ return service.Ping ();
+ }
+
+ ///
+ /// Sends a Ping with the specified to the client of the
+ /// instance with the specified .
+ ///
+ ///
+ /// true if the instance receives a Pong from the client
+ /// in a time; otherwise, false.
///
///
/// A that contains a message to send.
@@ -417,7 +442,7 @@ namespace WebSocketSharp.Server
///
/// Sends a binary data to the client of the instance
- /// with the specified ID.
+ /// with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -444,7 +469,7 @@ namespace WebSocketSharp.Server
///
/// Sends a text data to the client of the instance
- /// with the specified ID.
+ /// with the specified .
///
///
/// true if is successfully sent; otherwise, false.
@@ -471,12 +496,69 @@ namespace WebSocketSharp.Server
internal void Stop ()
{
- stop (0, null, true);
+ stopSweepTimer ();
+ lock (_sync)
+ {
+ if (_stopped)
+ return;
+
+ _stopped = true;
+ foreach (var service in copy ().Values)
+ service.Stop ();
+ }
}
internal void Stop (ushort code, string reason)
{
- stop (code, reason, false);
+ stopSweepTimer ();
+ lock (_sync)
+ {
+ if (_stopped)
+ return;
+
+ _stopped = true;
+ foreach (var service in copy ().Values)
+ service.Stop (code, reason);
+ }
+ }
+
+ internal void StopServiceInstance (string id)
+ {
+ WebSocketService service;
+ if (!TryGetServiceInstance (id, out service))
+ {
+ _logger.Error (
+ "The WebSocket service instance with the specified ID not found.\nID: " + id);
+ return;
+ }
+
+ service.Stop ();
+ }
+
+ internal void StopServiceInstance (ushort code, string reason, string id)
+ {
+ WebSocketService service;
+ if (!TryGetServiceInstance (id, out service))
+ {
+ _logger.Error (
+ "The WebSocket service instance with the specified ID not found.\nID: " + id);
+ return;
+ }
+
+ service.Stop (code, reason);
+ }
+
+ internal void StopServiceInstance (CloseStatusCode code, string reason, string id)
+ {
+ WebSocketService service;
+ if (!TryGetServiceInstance (id, out service))
+ {
+ _logger.Error (
+ "The WebSocket service instance with the specified ID not found.\nID: " + id);
+ return;
+ }
+
+ service.Stop (code, reason);
}
#endregion
@@ -520,7 +602,7 @@ namespace WebSocketSharp.Server
}
///
- /// Tries to get the instance with the specified ID.
+ /// Tries to get the instance with the specified .
///
///
/// true if the instance with