websocket-sharp/websocket-sharp/Net/ListenerAsyncResult.cs

223 lines
5.0 KiB
C#

//
// ListenerAsyncResult.cs
// Copied from System.Net.ListenerAsyncResult.cs
//
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
// Copyright (c) 2005 Ximian, Inc (http://www.ximian.com)
//
// 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.
//
using System;
using System.Net;
using System.Threading;
namespace WebSocketSharp.Net {
class ListenerAsyncResult : IAsyncResult
{
#region Private Static Field
static WaitCallback InvokeCB = new WaitCallback (InvokeCallback);
#endregion
#region Private Fields
AsyncCallback cb;
bool completed;
HttpListenerContext context;
Exception exception;
ListenerAsyncResult forward;
ManualResetEvent handle;
object locker;
object state;
bool synch;
#endregion
#region Internal Fields
internal bool EndCalled;
internal bool InGet;
#endregion
#region Constructor
public ListenerAsyncResult (AsyncCallback cb, object state)
{
this.cb = cb;
this.state = state;
this.locker = new object();
}
#endregion
#region Properties
public object AsyncState {
get {
if (forward != null)
return forward.AsyncState;
return state;
}
}
public WaitHandle AsyncWaitHandle {
get {
if (forward != null)
return forward.AsyncWaitHandle;
lock (locker) {
if (handle == null)
handle = new ManualResetEvent (completed);
}
return handle;
}
}
public bool CompletedSynchronously {
get {
if (forward != null)
return forward.CompletedSynchronously;
return synch;
}
}
public bool IsCompleted {
get {
if (forward != null)
return forward.IsCompleted;
lock (locker) {
return completed;
}
}
}
#endregion
#region Private Method
static void InvokeCallback (object o)
{
ListenerAsyncResult ares = (ListenerAsyncResult) o;
if (ares.forward != null) {
InvokeCallback (ares.forward);
return;
}
try {
ares.cb (ares);
} catch {
}
}
#endregion
#region Internal Methods
internal void Complete (Exception exc)
{
if (forward != null) {
forward.Complete (exc);
return;
}
exception = exc;
if (InGet && (exc is ObjectDisposedException))
exception = new HttpListenerException (500, "Listener closed");
lock (locker) {
completed = true;
if (handle != null)
handle.Set ();
if (cb != null)
ThreadPool.UnsafeQueueUserWorkItem (InvokeCB, this);
}
}
internal void Complete (HttpListenerContext context)
{
Complete (context, false);
}
internal void Complete (HttpListenerContext context, bool synch)
{
if (forward != null) {
forward.Complete (context, synch);
return;
}
this.synch = synch;
this.context = context;
lock (locker) {
AuthenticationSchemes schemes = context.Listener.SelectAuthenticationScheme (context);
if ((schemes == AuthenticationSchemes.Basic || context.Listener.AuthenticationSchemes == AuthenticationSchemes.Negotiate) && context.Request.Headers ["Authorization"] == null) {
context.Response.StatusCode = 401;
context.Response.Headers ["WWW-Authenticate"] = schemes + " realm=\"" + context.Listener.Realm + "\"";
context.Response.OutputStream.Close ();
IAsyncResult ares = context.Listener.BeginGetContext (cb, state);
this.forward = (ListenerAsyncResult) ares;
lock (forward.locker) {
if (handle != null)
forward.handle = handle;
}
ListenerAsyncResult next = forward;
for (int i = 0; next.forward != null; i++) {
if (i > 20)
Complete (new HttpListenerException (400, "Too many authentication errors"));
next = next.forward;
}
} else {
completed = true;
if (handle != null)
handle.Set ();
if (cb != null)
ThreadPool.UnsafeQueueUserWorkItem (InvokeCB, this);
}
}
}
internal HttpListenerContext GetContext ()
{
if (forward != null)
return forward.GetContext ();
if (exception != null)
throw exception;
return context;
}
#endregion
}
}