//-----------------------------------------------------------------------
//
// 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;
}
}
}
}
}
}