1 #define EMBEDDED_IN_1_0
4 // System.Net.HttpListener
7 // Gonzalo Paniagua Javier (gonzalo@novell.com)
9 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Threading;
36 using System; using System.Net; namespace MonoHttp {
37 internal class HttpListener : IDisposable {
38 AuthenticationSchemes auth_schemes;
39 HttpListenerPrefixCollection prefixes;
40 AuthenticationSchemeSelector auth_selector;
42 bool ignore_write_exceptions;
43 bool unsafe_ntlm_auth;
47 Hashtable registry; // Dictionary<HttpListenerContext,HttpListenerContext>
48 ArrayList ctx_queue; // List<HttpListenerContext> ctx_queue;
49 ArrayList wait_queue; // List<ListenerAsyncResult> wait_queue;
51 public HttpListener ()
53 prefixes = new HttpListenerPrefixCollection (this);
54 registry = new Hashtable ();
55 ctx_queue = new ArrayList ();
56 wait_queue = new ArrayList ();
57 auth_schemes = AuthenticationSchemes.Anonymous;
60 // TODO: Digest, NTLM and Negotiate require ControlPrincipal
61 public AuthenticationSchemes AuthenticationSchemes {
62 get { return auth_schemes; }
69 //TODO: when is this called?
70 public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate {
71 get { return auth_selector; }
74 auth_selector = value;
78 public bool IgnoreWriteExceptions {
79 get { return ignore_write_exceptions; }
82 ignore_write_exceptions = value;
86 public bool IsListening {
87 get { return listening; }
90 public static bool IsSupported {
94 public HttpListenerPrefixCollection Prefixes {
102 public string Realm {
103 get { return realm; }
110 [MonoTODO ("Support for NTLM needs some loving.")]
111 public bool UnsafeConnectionNtlmAuthentication {
112 get { return unsafe_ntlm_auth; }
115 unsafe_ntlm_auth = value;
145 void Close (bool force)
148 EndPointManager.RemoveListener (this);
152 void Cleanup (bool close_existing)
155 if (close_existing) {
156 foreach (HttpListenerContext context in registry.Keys) {
157 context.Connection.Close ();
159 registry.Clear (); // Just in case.
163 foreach (HttpListenerContext context in ctx_queue)
164 context.Connection.Close ();
170 foreach (ListenerAsyncResult ares in wait_queue) {
171 ares.Complete ("Listener was closed.");
178 public IAsyncResult BeginGetContext (AsyncCallback callback, Object state)
182 throw new InvalidOperationException ("Please, call Start before using this method.");
184 ListenerAsyncResult ares = new ListenerAsyncResult (callback, state);
186 // lock wait_queue early to avoid race conditions
189 HttpListenerContext ctx = GetContextFromQueue ();
191 ares.Complete (ctx, true);
196 wait_queue.Add (ares);
202 public HttpListenerContext EndGetContext (IAsyncResult asyncResult)
205 if (asyncResult == null)
206 throw new ArgumentNullException ("asyncResult");
208 ListenerAsyncResult ares = asyncResult as ListenerAsyncResult;
210 throw new ArgumentException ("Wrong IAsyncResult.", "asyncResult");
212 if (!ares.IsCompleted)
213 ares.AsyncWaitHandle.WaitOne ();
216 int idx = wait_queue.IndexOf (ares);
218 wait_queue.RemoveAt (idx);
221 HttpListenerContext context = ares.GetContext ();
222 if (auth_schemes != AuthenticationSchemes.Anonymous) {
223 context.ParseAuthentication ();
225 return context; // This will throw on error.
228 public HttpListenerContext GetContext ()
230 // The prefixes are not checked when using the async interface!?
231 if (prefixes.Count == 0)
232 throw new InvalidOperationException ("Please, call AddPrefix before using this method.");
234 IAsyncResult ares = BeginGetContext (null, null);
235 return EndGetContext (ares);
244 EndPointManager.AddListener (this);
255 void IDisposable.Dispose ()
260 Close (true); //TODO: Should we force here or not?
264 internal void CheckDisposed ()
267 throw new ObjectDisposedException (GetType ().ToString ());
270 // Must be called with a lock on ctx_queue
271 HttpListenerContext GetContextFromQueue ()
273 if (ctx_queue.Count == 0)
276 HttpListenerContext context = (HttpListenerContext) ctx_queue [0];
277 ctx_queue.RemoveAt (0);
281 internal void RegisterContext (HttpListenerContext context)
284 Monitor.Enter (registry);
285 registry [context] = context;
286 Monitor.Enter (wait_queue);
287 Monitor.Enter (ctx_queue);
288 if (wait_queue.Count == 0) {
289 ctx_queue.Add (context);
291 ListenerAsyncResult ares = (ListenerAsyncResult) wait_queue [0];
292 wait_queue.RemoveAt (0);
293 ares.Complete (context);
296 Monitor.Exit (ctx_queue);
297 Monitor.Exit (wait_queue);
298 Monitor.Exit (registry);
302 internal void UnregisterContext (HttpListenerContext context)
305 Monitor.Enter (registry);
306 Monitor.Enter (ctx_queue);
307 int idx = ctx_queue.IndexOf (context);
309 ctx_queue.RemoveAt (idx);
310 registry.Remove (context);
312 Monitor.Exit (ctx_queue);
313 Monitor.Exit (registry);