| // | 
| // ListenerAsyncResult.cs | 
| //    Copied from System.Net.ListenerAsyncResult | 
| // | 
| // 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 | 
|     { | 
|         static WaitCallback InvokeCB = new WaitCallback (InvokeCallback); | 
|   | 
|         AsyncCallback       cb; | 
|         bool                completed; | 
|         HttpListenerContext context; | 
|         Exception           exception; | 
|         ListenerAsyncResult forward; | 
|         ManualResetEvent    handle; | 
|         object              locker; | 
|         object              state; | 
|         bool                synch; | 
|   | 
|         internal bool EndCalled; | 
|         internal bool InGet; | 
|   | 
|         public ListenerAsyncResult (AsyncCallback cb, object state) | 
|         { | 
|             this.cb     = cb; | 
|             this.state  = state; | 
|             this.locker = new object(); | 
|         } | 
|   | 
|         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; | 
|                 } | 
|             } | 
|         } | 
|   | 
|         static void InvokeCallback (object o) | 
|         { | 
|             ListenerAsyncResult ares = (ListenerAsyncResult) o; | 
|             if (ares.forward != null) { | 
|                 InvokeCallback (ares.forward); | 
|                 return; | 
|             } | 
|             try { | 
|                 ares.cb (ares); | 
|             } catch { | 
|             } | 
|         } | 
|   | 
|         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; | 
|         } | 
|     } | 
| } |