Refactored HttpListener.cs
This commit is contained in:
		@@ -58,8 +58,10 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
    private Func<HttpListenerRequest, AuthenticationSchemes>     _authSchemeSelector;
 | 
					    private Func<HttpListenerRequest, AuthenticationSchemes>     _authSchemeSelector;
 | 
				
			||||||
    private string                                               _certFolderPath;
 | 
					    private string                                               _certFolderPath;
 | 
				
			||||||
    private Dictionary<HttpConnection, HttpConnection>           _connections;
 | 
					    private Dictionary<HttpConnection, HttpConnection>           _connections;
 | 
				
			||||||
    private List<HttpListenerContext>                            _contextQueue;
 | 
					    private object                                               _connectionsSync;
 | 
				
			||||||
    private Func<IIdentity, NetworkCredential>                   _credentialsFinder;
 | 
					    private List<HttpListenerContext>                            _ctxQueue;
 | 
				
			||||||
 | 
					    private object                                               _ctxQueueSync;
 | 
				
			||||||
 | 
					    private Func<IIdentity, NetworkCredential>                   _credFinder;
 | 
				
			||||||
    private X509Certificate2                                     _defaultCert;
 | 
					    private X509Certificate2                                     _defaultCert;
 | 
				
			||||||
    private bool                                                 _disposed;
 | 
					    private bool                                                 _disposed;
 | 
				
			||||||
    private bool                                                 _ignoreWriteExceptions;
 | 
					    private bool                                                 _ignoreWriteExceptions;
 | 
				
			||||||
@@ -67,7 +69,9 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
    private HttpListenerPrefixCollection                         _prefixes;
 | 
					    private HttpListenerPrefixCollection                         _prefixes;
 | 
				
			||||||
    private string                                               _realm;
 | 
					    private string                                               _realm;
 | 
				
			||||||
    private Dictionary<HttpListenerContext, HttpListenerContext> _registry;
 | 
					    private Dictionary<HttpListenerContext, HttpListenerContext> _registry;
 | 
				
			||||||
 | 
					    private object                                               _registrySync;
 | 
				
			||||||
    private List<ListenerAsyncResult>                            _waitQueue;
 | 
					    private List<ListenerAsyncResult>                            _waitQueue;
 | 
				
			||||||
 | 
					    private object                                               _waitQueueSync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,11 +83,20 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
    public HttpListener ()
 | 
					    public HttpListener ()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      _authSchemes = AuthenticationSchemes.Anonymous;
 | 
					      _authSchemes = AuthenticationSchemes.Anonymous;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _connections = new Dictionary<HttpConnection, HttpConnection> ();
 | 
					      _connections = new Dictionary<HttpConnection, HttpConnection> ();
 | 
				
			||||||
      _contextQueue = new List<HttpListenerContext> ();
 | 
					      _connectionsSync = ((ICollection) _connections).SyncRoot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      _ctxQueue = new List<HttpListenerContext> ();
 | 
				
			||||||
 | 
					      _ctxQueueSync = ((ICollection) _ctxQueue).SyncRoot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _prefixes = new HttpListenerPrefixCollection (this);
 | 
					      _prefixes = new HttpListenerPrefixCollection (this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _registry = new Dictionary<HttpListenerContext, HttpListenerContext> ();
 | 
					      _registry = new Dictionary<HttpListenerContext, HttpListenerContext> ();
 | 
				
			||||||
 | 
					      _registrySync = ((ICollection) _registry).SyncRoot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _waitQueue = new List<ListenerAsyncResult> ();
 | 
					      _waitQueue = new List<ListenerAsyncResult> ();
 | 
				
			||||||
 | 
					      _waitQueueSync = ((ICollection) _waitQueue).SyncRoot;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
@@ -335,7 +348,7 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <value>
 | 
					    /// <value>
 | 
				
			||||||
    /// A <c>Func<<see cref="IIdentity"/>, <see cref="NetworkCredential"/>></c> delegate
 | 
					    /// A <c>Func<<see cref="IIdentity"/>, <see cref="NetworkCredential"/>></c> delegate
 | 
				
			||||||
    /// that invokes the method(s) used to find the credentials. The default value is a function
 | 
					    /// that invokes the method used to find the credentials. The default value is a function
 | 
				
			||||||
    /// that only returns <see langword="null"/>.
 | 
					    /// that only returns <see langword="null"/>.
 | 
				
			||||||
    /// </value>
 | 
					    /// </value>
 | 
				
			||||||
    /// <exception cref="ObjectDisposedException">
 | 
					    /// <exception cref="ObjectDisposedException">
 | 
				
			||||||
@@ -344,12 +357,12 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
    public Func<IIdentity, NetworkCredential> UserCredentialsFinder {
 | 
					    public Func<IIdentity, NetworkCredential> UserCredentialsFinder {
 | 
				
			||||||
      get {
 | 
					      get {
 | 
				
			||||||
        CheckDisposed ();
 | 
					        CheckDisposed ();
 | 
				
			||||||
        return _credentialsFinder ?? (_credentialsFinder = identity => null);
 | 
					        return _credFinder ?? (_credFinder = id => null);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      set {
 | 
					      set {
 | 
				
			||||||
        CheckDisposed ();
 | 
					        CheckDisposed ();
 | 
				
			||||||
        _credentialsFinder = value;
 | 
					        _credFinder = value;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -359,7 +372,7 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private void cleanup (bool force)
 | 
					    private void cleanup (bool force)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _registry).SyncRoot) {
 | 
					      lock (_registrySync) {
 | 
				
			||||||
        if (!force)
 | 
					        if (!force)
 | 
				
			||||||
          sendServiceUnavailable ();
 | 
					          sendServiceUnavailable ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -371,39 +384,39 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private void cleanupConnections ()
 | 
					    private void cleanupConnections ()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _connections).SyncRoot) {
 | 
					      lock (_connectionsSync) {
 | 
				
			||||||
        if (_connections.Count == 0)
 | 
					        if (_connections.Count == 0)
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Need to copy this since closing will call RemoveConnection.
 | 
					        // Need to copy this since closing will call RemoveConnection.
 | 
				
			||||||
        var keys = _connections.Keys;
 | 
					        var keys = _connections.Keys;
 | 
				
			||||||
        var conns = new HttpConnection [keys.Count];
 | 
					        var conns = new HttpConnection[keys.Count];
 | 
				
			||||||
        keys.CopyTo (conns, 0);
 | 
					        keys.CopyTo (conns, 0);
 | 
				
			||||||
        _connections.Clear ();
 | 
					        _connections.Clear ();
 | 
				
			||||||
        for (var i = conns.Length - 1; i >= 0; i--)
 | 
					        for (var i = conns.Length - 1; i >= 0; i--)
 | 
				
			||||||
          conns [i].Close (true);
 | 
					          conns[i].Close (true);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void cleanupContextRegistry ()
 | 
					    private void cleanupContextRegistry ()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _registry).SyncRoot) {
 | 
					      lock (_registrySync) {
 | 
				
			||||||
        if (_registry.Count == 0)
 | 
					        if (_registry.Count == 0)
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Need to copy this since closing will call UnregisterContext.
 | 
					        // Need to copy this since closing will call UnregisterContext.
 | 
				
			||||||
        var keys = _registry.Keys;
 | 
					        var keys = _registry.Keys;
 | 
				
			||||||
        var all = new HttpListenerContext [keys.Count];
 | 
					        var all = new HttpListenerContext[keys.Count];
 | 
				
			||||||
        keys.CopyTo (all, 0);
 | 
					        keys.CopyTo (all, 0);
 | 
				
			||||||
        _registry.Clear ();
 | 
					        _registry.Clear ();
 | 
				
			||||||
        for (var i = all.Length - 1; i >= 0; i--)
 | 
					        for (var i = all.Length - 1; i >= 0; i--)
 | 
				
			||||||
          all [i].Connection.Close (true);
 | 
					          all[i].Connection.Close (true);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void cleanupWaitQueue ()
 | 
					    private void cleanupWaitQueue ()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _waitQueue).SyncRoot) {
 | 
					      lock (_waitQueueSync) {
 | 
				
			||||||
        if (_waitQueue.Count == 0)
 | 
					        if (_waitQueue.Count == 0)
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -421,28 +434,28 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
      cleanup (force);
 | 
					      cleanup (force);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Must be called with a lock on _contextQueue.
 | 
					    // Must be called with a lock on _ctxQueue.
 | 
				
			||||||
    private HttpListenerContext getContextFromQueue ()
 | 
					    private HttpListenerContext getContextFromQueue ()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      if (_contextQueue.Count == 0)
 | 
					      if (_ctxQueue.Count == 0)
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var context = _contextQueue [0];
 | 
					      var ctx = _ctxQueue[0];
 | 
				
			||||||
      _contextQueue.RemoveAt (0);
 | 
					      _ctxQueue.RemoveAt (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return context;
 | 
					      return ctx;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void sendServiceUnavailable ()
 | 
					    private void sendServiceUnavailable ()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _contextQueue).SyncRoot) {
 | 
					      lock (_ctxQueueSync) {
 | 
				
			||||||
        if (_contextQueue.Count == 0)
 | 
					        if (_ctxQueue.Count == 0)
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var contexts = _contextQueue.ToArray ();
 | 
					        var ctxs = _ctxQueue.ToArray ();
 | 
				
			||||||
        _contextQueue.Clear ();
 | 
					        _ctxQueue.Clear ();
 | 
				
			||||||
        foreach (var context in contexts) {
 | 
					        foreach (var ctx in ctxs) {
 | 
				
			||||||
          var res = context.Response;
 | 
					          var res = ctx.Response;
 | 
				
			||||||
          res.StatusCode = (int) HttpStatusCode.ServiceUnavailable;
 | 
					          res.StatusCode = (int) HttpStatusCode.ServiceUnavailable;
 | 
				
			||||||
          res.Close ();
 | 
					          res.Close ();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -455,8 +468,8 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    internal void AddConnection (HttpConnection connection)
 | 
					    internal void AddConnection (HttpConnection connection)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _connections).SyncRoot)
 | 
					      lock (_connectionsSync)
 | 
				
			||||||
        _connections [connection] = connection;
 | 
					        _connections[connection] = connection;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal ListenerAsyncResult BeginGetContext (ListenerAsyncResult asyncResult)
 | 
					    internal ListenerAsyncResult BeginGetContext (ListenerAsyncResult asyncResult)
 | 
				
			||||||
@@ -469,11 +482,11 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
        throw new InvalidOperationException ("Please, call Start before using this method.");
 | 
					        throw new InvalidOperationException ("Please, call Start before using this method.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Lock _waitQueue early to avoid race conditions.
 | 
					      // Lock _waitQueue early to avoid race conditions.
 | 
				
			||||||
      lock (((ICollection) _waitQueue).SyncRoot) {
 | 
					      lock (_waitQueueSync) {
 | 
				
			||||||
        lock (((ICollection) _contextQueue).SyncRoot) {
 | 
					        lock (_ctxQueueSync) {
 | 
				
			||||||
          var context = getContextFromQueue ();
 | 
					          var ctx = getContextFromQueue ();
 | 
				
			||||||
          if (context != null) {
 | 
					          if (ctx != null) {
 | 
				
			||||||
            asyncResult.Complete (context, true);
 | 
					            asyncResult.Complete (ctx, true);
 | 
				
			||||||
            return asyncResult;
 | 
					            return asyncResult;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -492,17 +505,17 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    internal void RegisterContext (HttpListenerContext context)
 | 
					    internal void RegisterContext (HttpListenerContext context)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _registry).SyncRoot)
 | 
					      lock (_registrySync)
 | 
				
			||||||
        _registry [context] = context;
 | 
					        _registry[context] = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ListenerAsyncResult ares = null;
 | 
					      ListenerAsyncResult ares = null;
 | 
				
			||||||
      lock (((ICollection) _waitQueue).SyncRoot) {
 | 
					      lock (_waitQueueSync) {
 | 
				
			||||||
        if (_waitQueue.Count == 0) {
 | 
					        if (_waitQueue.Count == 0) {
 | 
				
			||||||
          lock (((ICollection) _contextQueue).SyncRoot)
 | 
					          lock (_ctxQueueSync)
 | 
				
			||||||
            _contextQueue.Add (context);
 | 
					            _ctxQueue.Add (context);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
          ares = _waitQueue [0];
 | 
					          ares = _waitQueue[0];
 | 
				
			||||||
          _waitQueue.RemoveAt (0);
 | 
					          _waitQueue.RemoveAt (0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -513,7 +526,7 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    internal void RemoveConnection (HttpConnection connection)
 | 
					    internal void RemoveConnection (HttpConnection connection)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _connections).SyncRoot)
 | 
					      lock (_connectionsSync)
 | 
				
			||||||
        _connections.Remove (connection);
 | 
					        _connections.Remove (connection);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -526,13 +539,13 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    internal void UnregisterContext (HttpListenerContext context)
 | 
					    internal void UnregisterContext (HttpListenerContext context)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      lock (((ICollection) _registry).SyncRoot)
 | 
					      lock (_registrySync)
 | 
				
			||||||
        _registry.Remove (context);
 | 
					        _registry.Remove (context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      lock (((ICollection) _contextQueue).SyncRoot) {
 | 
					      lock (_ctxQueueSync) {
 | 
				
			||||||
        var i = _contextQueue.IndexOf (context);
 | 
					        var i = _ctxQueue.IndexOf (context);
 | 
				
			||||||
        if (i >= 0)
 | 
					        if (i >= 0)
 | 
				
			||||||
          _contextQueue.RemoveAt (i);
 | 
					          _ctxQueue.RemoveAt (i);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -643,18 +656,18 @@ namespace WebSocketSharp.Net
 | 
				
			|||||||
      if (!ares.IsCompleted)
 | 
					      if (!ares.IsCompleted)
 | 
				
			||||||
        ares.AsyncWaitHandle.WaitOne ();
 | 
					        ares.AsyncWaitHandle.WaitOne ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      lock (((ICollection) _waitQueue).SyncRoot) {
 | 
					      lock (_waitQueueSync) {
 | 
				
			||||||
        var i = _waitQueue.IndexOf (ares);
 | 
					        var i = _waitQueue.IndexOf (ares);
 | 
				
			||||||
        if (i >= 0)
 | 
					        if (i >= 0)
 | 
				
			||||||
          _waitQueue.RemoveAt (i);
 | 
					          _waitQueue.RemoveAt (i);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var context = ares.GetContext ();
 | 
					      var ctx = ares.GetContext ();
 | 
				
			||||||
      var scheme = SelectAuthenticationScheme (context);
 | 
					      var schm = SelectAuthenticationScheme (ctx);
 | 
				
			||||||
      if (scheme != AuthenticationSchemes.Anonymous)
 | 
					      if (schm != AuthenticationSchemes.Anonymous)
 | 
				
			||||||
        context.SetUser (scheme, Realm, UserCredentialsFinder);
 | 
					        ctx.SetUser (schm, Realm, UserCredentialsFinder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return context; // This will throw on error.
 | 
					      return ctx; // This will throw on error.
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user