diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs index 4f1184d6..cc5599de 100644 --- a/websocket-sharp/Server/HttpServer.cs +++ b/websocket-sharp/Server/HttpServer.cs @@ -31,7 +31,7 @@ #region Contributors /* * Contributors: - * Juan Manuel Lallana + * - Juan Manuel Lallana */ #endregion @@ -79,7 +79,7 @@ namespace WebSocketSharp.Server /// An instance initialized by this constructor listens for the incoming requests on port 80. /// public HttpServer () - : this (80) + : this (80, false) { } @@ -89,11 +89,11 @@ namespace WebSocketSharp.Server /// /// /// - /// An instance initialized by this constructor listens for the incoming requests on - /// . + /// An instance initialized by this constructor listens for the incoming requests + /// on . /// /// - /// And if is 443, that instance provides a secure connection. + /// If is 443, that instance provides a secure connection. /// /// /// @@ -112,30 +112,30 @@ namespace WebSocketSharp.Server /// and . /// /// - /// An instance initialized by this constructor listens for the incoming requests on - /// . + /// An instance initialized by this constructor listens for the incoming requests + /// on . /// /// /// An that represents the port number on which to listen. /// /// - /// A that indicates providing a secure connection or not. (true - /// indicates providing a secure connection.) + /// A that indicates providing a secure connection or not. + /// (true indicates providing a secure connection.) /// - /// - /// isn't between 1 and 65535. - /// /// /// Pair of and is invalid. /// + /// + /// isn't between 1 and 65535. + /// public HttpServer (int port, bool secure) { if (!port.IsPortNumber ()) - throw new ArgumentOutOfRangeException ("port", "Must be between 1 and 65535: " + port); + throw new ArgumentOutOfRangeException ("port", "Not between 1 and 65535: " + port); if ((port == 80 && secure) || (port == 443 && !secure)) throw new ArgumentException ( - String.Format ("Invalid pair of 'port' and 'secure': {0}, {1}", port, secure)); + String.Format ("An invalid pair of 'port' and 'secure': {0}, {1}", port, secure)); _port = port; _secure = secure; @@ -146,8 +146,7 @@ namespace WebSocketSharp.Server _sync = new object (); var os = Environment.OSVersion; - if (os.Platform != PlatformID.Unix && os.Platform != PlatformID.MacOSX) - _windows = true; + _windows = os.Platform != PlatformID.Unix && os.Platform != PlatformID.MacOSX; var prefix = String.Format ("http{0}://*:{1}/", _secure ? "s" : "", _port); _listener.Prefixes.Add (prefix); @@ -161,9 +160,9 @@ namespace WebSocketSharp.Server /// Gets or sets the scheme used to authenticate the clients. /// /// - /// One of the enum values, indicates - /// the scheme used to authenticate the clients. - /// The default value is . + /// One of the enum values, + /// indicates the scheme used to authenticate the clients. The default value is + /// . /// public AuthenticationSchemes AuthenticationSchemes { get { @@ -171,8 +170,11 @@ namespace WebSocketSharp.Server } set { - if (!canSet ("AuthenticationSchemes")) + var msg = _state.CheckIfStartable (); + if (msg != null) { + _logger.Error (msg); return; + } _listener.AuthenticationSchemes = value; } @@ -182,7 +184,8 @@ namespace WebSocketSharp.Server /// Gets or sets the certificate used to authenticate the server on the secure connection. /// /// - /// A used to authenticate the server. + /// A that represents the certificate used to authenticate + /// the server. /// public X509Certificate2 Certificate { get { @@ -190,8 +193,11 @@ namespace WebSocketSharp.Server } set { - if (!canSet ("Certificate")) + var msg = _state.CheckIfStartable (); + if (msg != null) { + _logger.Error (msg); return; + } if (EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath)) _logger.Warn ("The server certificate associated with the port number already exists."); @@ -225,12 +231,12 @@ namespace WebSocketSharp.Server } /// - /// Gets or sets a value indicating whether the server cleans up the inactive sessions in the - /// WebSocket services periodically. + /// Gets or sets a value indicating whether the server cleans up the inactive sessions + /// in the WebSocket services periodically. /// /// - /// true if the server cleans up the inactive sessions every 60 seconds; otherwise, - /// false. The default value is true. + /// true if the server cleans up the inactive sessions every 60 seconds; + /// otherwise, false. The default value is true. /// public bool KeepClean { get { @@ -275,8 +281,8 @@ namespace WebSocketSharp.Server /// Gets or sets the name of the realm associated with the server. /// /// - /// A that represents the name of the realm. The default value is - /// SECRET AREA. + /// A that represents the name of the realm. + /// The default value is "SECRET AREA". /// public string Realm { get { @@ -284,8 +290,11 @@ namespace WebSocketSharp.Server } set { - if (!canSet ("Realm")) + var msg = _state.CheckIfStartable (); + if (msg != null) { + _logger.Error (msg); return; + } _listener.Realm = value; } @@ -295,19 +304,22 @@ namespace WebSocketSharp.Server /// Gets or sets the document root path of the server. /// /// - /// A that represents the document root path of the server. The default - /// value is ./Public. + /// A that represents the document root path of the server. + /// The default value is "./Public". /// public string RootPath { get { - return _rootPath.IsNullOrEmpty () - ? (_rootPath = "./Public") - : _rootPath; + return _rootPath != null && _rootPath.Length > 0 + ? _rootPath + : (_rootPath = "./Public"); } set { - if (!canSet ("RootPath")) + var msg = _state.CheckIfStartable (); + if (msg != null) { + _logger.Error (msg); return; + } _rootPath = value; } @@ -328,8 +340,11 @@ namespace WebSocketSharp.Server } set { - if (!canSet ("UserCredentialsFinder")) + var msg = _state.CheckIfStartable (); + if (msg != null) { + _logger.Error (msg); return; + } _listener.UserCredentialsFinder = value; } @@ -416,104 +431,6 @@ namespace WebSocketSharp.Server _state = ServerState.Stop; } - private void acceptHttpRequest (HttpListenerContext context) - { - var args = new HttpRequestEventArgs (context); - var method = context.Request.HttpMethod; - if (method == "GET") { - if (OnGet != null) { - OnGet (this, args); - return; - } - } - else if (method == "HEAD") { - if (OnHead != null) { - OnHead (this, args); - return; - } - } - else if (method == "POST") { - if (OnPost != null) { - OnPost (this, args); - return; - } - } - else if (method == "PUT") { - if (OnPut != null) { - OnPut (this, args); - return; - } - } - else if (method == "DELETE") { - if (OnDelete != null) { - OnDelete (this, args); - return; - } - } - else if (method == "OPTIONS") { - if (OnOptions != null) { - OnOptions (this, args); - return; - } - } - else if (method == "TRACE") { - if (OnTrace != null) { - OnTrace (this, args); - return; - } - } - else if (method == "CONNECT") { - if (OnConnect != null) { - OnConnect (this, args); - return; - } - } - else if (method == "PATCH") { - if (OnPatch != null) { - OnPatch (this, args); - return; - } - } - - context.Response.StatusCode = (int) HttpStatusCode.NotImplemented; - } - - private void acceptRequestAsync (HttpListenerContext context) - { - ThreadPool.QueueUserWorkItem ( - state => { - try { - var authScheme = _listener.SelectAuthenticationScheme (context); - if (authScheme != AuthenticationSchemes.Anonymous && - !authenticateRequest (authScheme, context)) - return; - - if (context.Request.IsUpgradeTo ("websocket")) { - acceptWebSocketRequest (context.AcceptWebSocket (null, _logger)); - return; - } - - acceptHttpRequest (context); - context.Response.Close (); - } - catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - context.Connection.Close (true); - } - }); - } - - private void acceptWebSocketRequest (HttpListenerWebSocketContext context) - { - WebSocketServiceHost host; - if (!_services.TryGetServiceHostInternally (context.RequestUri.AbsolutePath, out host)) { - context.Close (HttpStatusCode.NotImplemented); - return; - } - - host.StartSession (context); - } - private bool authenticateRequest (AuthenticationSchemes scheme, HttpListenerContext context) { if (context.Request.IsAuthenticated) @@ -531,34 +448,87 @@ namespace WebSocketSharp.Server return false; } - private bool canSet (string property) - { - if (_state == ServerState.Start || _state == ServerState.ShuttingDown) { - _logger.Error ( - String.Format ( - "Set operation of {0} isn't available because the server has already started.", - property)); - - return false; - } - - return true; - } - - private string checkIfCertExists () + private string checkIfCertificateExists () { return _secure && !EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath) && - Certificate == null + _listener.DefaultCertificate == null ? "The secure connection requires a server certificate." : null; } + private void processHttpRequest (HttpListenerContext context) + { + var method = context.Request.HttpMethod; + var evt = method == "GET" + ? OnGet + : method == "HEAD" + ? OnHead + : method == "POST" + ? OnPost + : method == "PUT" + ? OnPut + : method == "DELETE" + ? OnDelete + : method == "OPTIONS" + ? OnOptions + : method == "TRACE" + ? OnTrace + : method == "CONNECT" + ? OnConnect + : method == "PATCH" + ? OnPatch + : null; + + if (evt != null) { + evt (this, new HttpRequestEventArgs (context)); + return; + } + + context.Response.StatusCode = (int) HttpStatusCode.NotImplemented; + } + + private void processRequestAsync (HttpListenerContext context) + { + ThreadPool.QueueUserWorkItem ( + state => { + try { + var authScheme = _listener.SelectAuthenticationScheme (context); + if (authScheme != AuthenticationSchemes.Anonymous && + !authenticateRequest (authScheme, context)) + return; + + if (context.Request.IsUpgradeTo ("websocket")) { + processWebSocketRequest (context.AcceptWebSocket (null, _logger)); + return; + } + + processHttpRequest (context); + context.Response.Close (); + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + context.Connection.Close (true); + } + }); + } + + private void processWebSocketRequest (HttpListenerWebSocketContext context) + { + WebSocketServiceHost host; + if (!_services.TryGetServiceHostInternally (context.RequestUri.AbsolutePath, out host)) { + context.Close (HttpStatusCode.NotImplemented); + return; + } + + host.StartSession (context); + } + private void receiveRequest () { while (true) { try { - acceptRequestAsync (_listener.GetContext ()); + processRequestAsync (_listener.GetContext ()); } catch (HttpListenerException ex) { _logger.Warn ("Receiving has been stopped.\nreason: " + ex.Message); @@ -602,9 +572,8 @@ namespace WebSocketSharp.Server /// A that represents the absolute path to the WebSocket service to add. /// /// - /// The type of the WebSocket service. - /// The TWithNew must inherit the class and must have a public - /// parameterless constructor. + /// The type of the WebSocket service. The TWithNew must inherit + /// the class and must have a public parameterless constructor. /// public void AddWebSocketService (string path) where TWithNew : WebSocketService, new () @@ -614,22 +583,22 @@ namespace WebSocketSharp.Server /// /// Adds the specified typed WebSocket service with the specified and - /// . + /// . /// /// /// - /// This method converts to URL-decoded string and removes '/' - /// from tail end of . + /// This method converts to URL-decoded string and + /// removes '/' from tail end of . /// /// - /// returns a initialized specified typed + /// returns an initialized specified typed /// instance. /// /// /// /// A that represents the absolute path to the WebSocket service to add. /// - /// + /// /// A Func<T> delegate that references the method used to initialize a new specified /// typed instance (a new /// instance). @@ -638,18 +607,18 @@ namespace WebSocketSharp.Server /// The type of the WebSocket service. The T must inherit the /// class. /// - public void AddWebSocketService (string path, Func constructor) + public void AddWebSocketService (string path, Func initializer) where T : WebSocketService { var msg = path.CheckIfValidServicePath () ?? - (constructor == null ? "'constructor' must not be null." : null); + (initializer == null ? "'initializer' is null." : null); if (msg != null) { _logger.Error (String.Format ("{0}\nservice path: {1}", msg, path)); return; } - var host = new WebSocketServiceHost (path, constructor, _logger); + var host = new WebSocketServiceHost (path, initializer, _logger); if (!KeepClean) host.KeepClean = false; @@ -660,13 +629,13 @@ namespace WebSocketSharp.Server /// Gets the contents of the file with the specified . /// /// - /// An array of that receives the contents of the file if it exists; - /// otherwise, . + /// An array of that receives the contents of the file, + /// or if it doesn't exist. /// /// /// A that represents the virtual path to the file to find. /// - public byte [] GetFile (string path) + public byte[] GetFile (string path) { var filePath = RootPath + path; if (_windows) @@ -681,12 +650,12 @@ namespace WebSocketSharp.Server /// Removes the WebSocket service with the specified . /// /// - /// This method converts to URL-decoded string and removes '/' - /// from tail end of . + /// 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. + /// true if the WebSocket service is successfully found and removed; + /// otherwise, false. /// /// /// A that represents the absolute path to the WebSocket service to find. @@ -708,7 +677,7 @@ namespace WebSocketSharp.Server public void Start () { lock (_sync) { - var msg = _state.CheckIfStartable () ?? checkIfCertExists (); + var msg = _state.CheckIfStartable () ?? checkIfCertificateExists (); if (msg != null) { _logger.Error (String.Format ("{0}\nstate: {1}\nsecure: {2}", msg, _state, _secure)); return; @@ -737,7 +706,7 @@ namespace WebSocketSharp.Server _state = ServerState.ShuttingDown; } - _services.Stop (new byte [0], true); + _services.Stop (new byte[0], true); stopListener (5000); _state = ServerState.Stop; @@ -755,7 +724,7 @@ namespace WebSocketSharp.Server /// public void Stop (ushort code, string reason) { - byte [] data = null; + byte[] data = null; lock (_sync) { var msg = _state.CheckIfStart () ?? code.CheckIfValidCloseStatusCode () ?? @@ -782,15 +751,15 @@ namespace WebSocketSharp.Server /// used to stop the WebSocket services. /// /// - /// One of the enum values, represents the status code indicating - /// the reasons for stop. + /// One of the enum values, represents the status code + /// indicating the reasons for stop. /// /// /// A that represents the reason for stop. /// public void Stop (CloseStatusCode code, string reason) { - byte [] data = null; + byte[] data = null; lock (_sync) { var msg = _state.CheckIfStart () ?? (data = ((ushort) code).Append (reason)).CheckIfValidControlData ("reason");