//----------------------------------------------------------------------- // // Copyright (c) Outercurve Foundation. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenIdOfflineProvider { using System; using System.Diagnostics.Contracts; using System.Globalization; using System.IO; using System.Net; using System.Threading; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Provider; /// /// An HTTP Listener that dispatches incoming requests for handling. /// internal class HttpHost : IDisposable { /// /// The HttpListener that waits for incoming requests. /// private readonly HttpListener listener; /// /// The thread that listens for incoming HTTP requests and dispatches them /// to the . /// private Thread listenerThread; /// /// The handler for incoming HTTP requests. /// private RequestHandler handler; /// /// Initializes a new instance of the class. /// /// The handler for incoming HTTP requests. private HttpHost(RequestHandler handler) { Contract.Requires(handler != null); this.Port = 45235; this.handler = handler; Random r = new Random(); tryAgain: try { this.listener = new HttpListener(); this.listener.Prefixes.Add(string.Format(CultureInfo.InvariantCulture, "http://localhost:{0}/", this.Port)); this.listener.Start(); } catch (HttpListenerException ex) { if (ex.Message.Contains("conflicts")) { this.Port += r.Next(1, 20); goto tryAgain; } throw; } this.listenerThread = new Thread(this.ProcessRequests); this.listenerThread.Start(); } /// /// The request handler delegate. /// /// Information on the incoming HTTP request. internal delegate void RequestHandler(HttpListenerContext context); /// /// Gets the port that HTTP requests are being listened for on. /// public int Port { get; private set; } /// /// Gets the base URI for all incoming web requests that will be received. /// public Uri BaseUri { get { return new Uri("http://localhost:" + this.Port.ToString() + "/"); } } /// /// Creates the HTTP host. /// /// The handler for incoming HTTP requests. /// The instantiated host. public static HttpHost CreateHost(RequestHandler handler) { Contract.Requires(handler != null); Contract.Ensures(Contract.Result() != null); return new HttpHost(handler); } #region IDisposable Members /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (disposing) { this.listener.Close(); this.listenerThread.Join(1000); this.listenerThread.Abort(); } } #endregion /// /// The HTTP listener thread body. /// private void ProcessRequests() { Contract.Requires(this.listener != null); while (true) { try { HttpListenerContext context = this.listener.GetContext(); this.handler(context); } catch (HttpListenerException ex) { if (this.listener.IsListening) { App.Logger.Error("Unexpected exception.", ex); } else { // the listener is probably being shut down App.Logger.Warn("HTTP listener is closing down.", ex); break; } } } } } }