Refactored HttpListener.cs
This commit is contained in:
parent
468c3ab881
commit
157dcf26b4
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user