#region License /* * WebSocketService.cs * * The MIT License * * Copyright (c) 2012-2014 sta.blockhead * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #endregion using System; using System.IO; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; namespace WebSocketSharp.Server { /// /// Exposes the methods and properties for a WebSocket service provided by the /// or . /// /// /// The WebSocketService class is an abstract class. /// public abstract class WebSocketService : IWebSocketSession { #region Private Fields private WebSocketContext _context; private Func _cookiesValidator; private Func _originValidator; private string _protocol; private WebSocketSessionManager _sessions; private DateTime _start; private WebSocket _websocket; #endregion #region Protected Constructors /// /// Initializes a new instance of the class. /// protected WebSocketService () { _start = DateTime.MaxValue; } #endregion #region Protected Properties /// /// Gets the logging functions. /// /// /// This property is available after the WebSocket connection has been established. /// /// /// A that provides the logging functions. /// protected Logger Log { get { return _websocket != null ? _websocket.Log : null; } } /// /// Gets the access to the sessions in the WebSocket service. /// /// /// This property is available after the WebSocket connection has been established. /// /// /// A that provides the access to the sessions. /// protected WebSocketSessionManager Sessions { get { return _sessions; } } #endregion #region Public Properties /// /// Gets the information in the WebSocket connection request. /// /// /// A that provides the access to the WebSocket connection /// request. /// public WebSocketContext Context { get { return _context; } } /// /// Gets or sets the delegate called to validate the HTTP cookies included in the WebSocket /// connection request. /// /// /// The delegate is called when the used in the current session /// validates the WebSocket connection request. /// /// /// /// A Func<CookieCollection, CookieCollection, bool> delegate that references /// the method(s) used to validate the cookies. 1st passed to /// this delegate contains the cookies to validate, if any. 2nd /// passed to this delegate receives the cookies to send to the client. /// /// /// This delegate should return true if the cookies are valid; otherwise, false. /// /// /// The default value is , and it does nothing to validate. /// /// public Func CookiesValidator { get { return _cookiesValidator; } set { _cookiesValidator = value; } } /// /// Gets the unique ID of the current session. /// /// /// A that represents the unique ID of the current session. /// public string ID { get; private set; } /// /// Gets or sets the delegate called to validate the Origin header included in the WebSocket /// connection request. /// /// /// The delegate is called when the used in the current session /// validates the WebSocket connection request. /// /// /// /// A Func<string, bool> delegate that references the method(s) used to validate /// the origin header. A passed to this delegate represents the value of /// the origin header to validate, if any. /// /// /// This delegate should return true if the origin header is valid; otherwise, /// false. /// /// /// The default value is , and it does nothing to validate. /// /// public Func OriginValidator { get { return _originValidator; } set { _originValidator = value; } } /// /// Gets or sets the subprotocol of the used in the current session. /// /// /// Set operation of this property is available before the WebSocket connection has been /// established. /// /// /// /// A that represents the subprotocol of the /// used in the current session if any. /// /// /// The value to set must be a token defined in /// RFC 2616. /// /// /// The default value is . /// /// public string Protocol { get { return _websocket != null ? _websocket.Protocol : _protocol ?? String.Empty; } set { if (State == WebSocketState.Connecting && value != null && value.Length > 0 && value.IsToken ()) _protocol = value; } } /// /// Gets the time that the current session has started. /// /// /// A that represents the time that the current session has started. /// public DateTime StartTime { get { return _start; } } /// /// Gets the state of the used in the current session. /// /// /// One of the enum values, indicates the state of the /// used in the current session. /// public WebSocketState State { get { return _websocket != null ? _websocket.ReadyState : WebSocketState.Connecting; } } #endregion #region Private Methods private string checkIfValidConnectionRequest (WebSocketContext context) { return _originValidator != null && !_originValidator (context.Origin) ? "Invalid Origin header." : _cookiesValidator != null && !_cookiesValidator (context.CookieCollection, context.WebSocket.CookieCollection) ? "Invalid Cookies." : null; } private void onClose (object sender, CloseEventArgs e) { if (ID == null) return; _sessions.Remove (ID); OnClose (e); } private void onError (object sender, ErrorEventArgs e) { OnError (e); } private void onMessage (object sender, MessageEventArgs e) { OnMessage (e); } private void onOpen (object sender, EventArgs e) { ID = _sessions.Add (this); if (ID == null) { _websocket.Close (CloseStatusCode.Away); return; } _start = DateTime.Now; OnOpen (); } #endregion #region Internal Methods internal void Start (WebSocketContext context, WebSocketSessionManager sessions) { _context = context; _sessions = sessions; _websocket = context.WebSocket; _websocket.Protocol = _protocol; _websocket.CustomHandshakeRequestChecker = checkIfValidConnectionRequest; _websocket.OnOpen += onOpen; _websocket.OnMessage += onMessage; _websocket.OnError += onError; _websocket.OnClose += onClose; _websocket.ConnectAsServer (); } #endregion #region Protected Methods /// /// Calls the method with the specified . /// /// /// A that represents the error message. /// protected void Error (string message) { if (message != null && message.Length > 0) OnError (new ErrorEventArgs (message)); } /// /// Called when the WebSocket connection used in the current session has been closed. /// /// /// A that represents the event data received by /// a event. /// protected virtual void OnClose (CloseEventArgs e) { } /// /// Called when the current session gets an error. /// /// /// A that represents the event data received by /// a event. /// protected virtual void OnError (ErrorEventArgs e) { } /// /// Called when the current session receives a message. /// /// /// A that represents the event data received by /// a event. /// protected virtual void OnMessage (MessageEventArgs e) { } /// /// Called when the WebSocket connection used in the current session has been established. /// protected virtual void OnOpen () { } /// /// Sends a binary to the client on the current session. /// /// /// An array of that represents the binary data to send. /// protected void Send (byte [] data) { if (_websocket != null) _websocket.Send (data); } /// /// Sends the specified as a binary data to the client on the current /// session. /// /// /// A that represents the file to send. /// protected void Send (FileInfo file) { if (_websocket != null) _websocket.Send (file); } /// /// Sends a text to the client on the current session. /// /// /// A that represents the text data to send. /// protected void Send (string data) { if (_websocket != null) _websocket.Send (data); } /// /// Sends a binary asynchronously to the client on the current session. /// /// /// This method doesn't wait for the send to be complete. /// /// /// An array of that represents the binary data to send. /// /// /// An Action<bool> delegate that references the method(s) called when the send is /// complete. A passed to this delegate is true if the send is /// complete successfully; otherwise, false. /// protected void SendAsync (byte [] data, Action completed) { if (_websocket != null) _websocket.SendAsync (data, completed); } /// /// Sends the specified as a binary data asynchronously to the client /// on the current session. /// /// /// This method doesn't wait for the send to be complete. /// /// /// A that represents the file to send. /// /// /// An Action<bool> delegate that references the method(s) called when the send is /// complete. A passed to this delegate is true if the send is /// complete successfully; otherwise, false. /// protected void SendAsync (FileInfo file, Action completed) { if (_websocket != null) _websocket.SendAsync (file, completed); } /// /// Sends a text asynchronously to the client on the current session. /// /// /// This method doesn't wait for the send to be complete. /// /// /// A that represents the text data to send. /// /// /// An Action<bool> delegate that references the method(s) called when the send is /// complete. A passed to this delegate is true if the send is /// complete successfully; otherwise, false. /// protected void SendAsync (string data, Action completed) { if (_websocket != null) _websocket.SendAsync (data, completed); } /// /// Sends a binary data from the specified asynchronously to the client on /// the current session. /// /// /// This method doesn't wait for the send to be complete. /// /// /// A from which contains the binary data to send. /// /// /// An that represents the number of bytes to send. /// /// /// An Action<bool> delegate that references the method(s) called when the send is /// complete. A passed to this delegate is true if the send is /// complete successfully; otherwise, false. /// protected void SendAsync (Stream stream, int length, Action completed) { if (_websocket != null) _websocket.SendAsync (stream, length, completed); } #endregion } }