[Pkg-mono-svn-commits] [xsp] 04/10: Imported Upstream version 4.2

Jo Shields directhex at moszumanska.debian.org
Mon Nov 30 15:25:19 UTC 2015


This is an automated email from the git hooks/post-receive script.

directhex pushed a commit to annotated tag debian/4.2-1
in repository xsp.

commit 1b3828afa30e4e5ab25f67293f7dbe64819ab055
Author: Jo Shields <directhex at apebox.org>
Date:   Mon Nov 30 14:23:23 2015 +0000

    Imported Upstream version 4.2
---
 configure                                          |  20 +-
 configure.ac                                       |   2 +-
 src/Mono.WebServer.XSP/Makefile.am                 |   2 +-
 src/Mono.WebServer.XSP/Makefile.in                 |   2 +-
 src/Mono.WebServer.XSP/Mono.WebServer.XSP.sources  |  10 +
 src/Mono.WebServer/ApplicationServer.cs            | 551 ++++++++++++
 src/Mono.WebServer/BaseApplicationHost.cs          | 273 ++++++
 src/Mono.WebServer/BaseRequestBroker.cs            | 268 ++++++
 src/Mono.WebServer/EndOfRequestHandler.cs          |  39 +
 src/Mono.WebServer/FinePlatformID.cs               |  35 +
 src/Mono.WebServer/HttpErrors.cs                   |  80 ++
 src/Mono.WebServer/IApplicationHost.cs             |  48 +
 src/Mono.WebServer/IRequestBroker.cs               |  38 +
 src/Mono.WebServer/IdentityToken.cs                |  51 ++
 src/Mono.WebServer/InitialWorkerRequest.cs         | 281 ++++++
 src/Mono.WebServer/LingeringNetworkStream.cs       | 100 +++
 src/Mono.WebServer/LockRecursionException.cs       |  54 ++
 src/Mono.WebServer/LockRecursionPolicy.cs          |  36 +
 src/Mono.WebServer/Log/FileLogger.cs               |  86 ++
 src/Mono.WebServer/Log/ILogger.cs                  |  35 +
 src/Mono.WebServer/Log/LogLevel.cs                 |  43 +
 src/Mono.WebServer/Log/Logger.cs                   | 151 ++++
 src/Mono.WebServer/Makefile.am                     |   2 +-
 src/Mono.WebServer/Makefile.in                     |   2 +-
 src/Mono.WebServer/MapPathEventArgs.cs             |  67 ++
 src/Mono.WebServer/MapPathEventHandler.cs          |  39 +
 src/Mono.WebServer/Mono.WebServer.sources          |  53 ++
 src/Mono.WebServer/MonoWorkerRequest.cs            | 626 +++++++++++++
 .../Options/ConfigurationManager.Fields.cs         | 137 +++
 src/Mono.WebServer/Options/ConfigurationManager.cs | 144 +++
 .../Options/ConfigurationManagerExtensions.cs      |  73 ++
 src/Mono.WebServer/Options/Descriptions.cs         |  93 ++
 .../Options/IHelpConfigurationManager.cs           |  37 +
 src/Mono.WebServer/Options/Options.cs              | 997 +++++++++++++++++++++
 .../Options/ServerConfigurationManager.cs          |  78 ++
 src/Mono.WebServer/Options/Settings/BoolSetting.cs |  39 +
 src/Mono.WebServer/Options/Settings/EnumSetting.cs |  50 ++
 src/Mono.WebServer/Options/Settings/ISetting.cs    |  44 +
 .../Options/Settings/Int32Setting.cs               |  39 +
 .../Options/Settings/NullableInt32Setting.cs       |  39 +
 .../Options/Settings/NullableSetting.cs            |  51 ++
 .../Options/Settings/NullableUInt16Setting.cs      |  39 +
 src/Mono.WebServer/Options/Settings/Parser.cs      |  31 +
 src/Mono.WebServer/Options/Settings/Setting.cs     |  95 ++
 .../Options/Settings/SettingSource.cs              |  38 +
 .../Options/Settings/SettingsCollection.cs         |  38 +
 .../Options/Settings/StringSetting.cs              |  45 +
 .../Options/Settings/UInt16Setting.cs              |  39 +
 .../Options/Settings/UInt32Setting.cs              |  39 +
 src/Mono.WebServer/Paths.cs                        |  85 ++
 src/Mono.WebServer/Platform.cs                     | 143 +++
 src/Mono.WebServer/RequestData.cs                  |  61 ++
 src/Mono.WebServer/RequestLineException.cs         |  38 +
 src/Mono.WebServer/SearchPattern.cs                | 195 ++++
 src/Mono.WebServer/UnregisterRequestEventArgs.cs   |  44 +
 .../UnregisterRequestEventHandler.cs               |  33 +
 src/Mono.WebServer/VPathToHost.cs                  | 153 ++++
 src/Mono.WebServer/Version.cs                      |  62 ++
 src/Mono.WebServer/WebSource.cs                    |  55 ++
 src/Mono.WebServer/WebTrace.cs                     | 137 +++
 src/Mono.WebServer/Worker.cs                       |  62 ++
 61 files changed, 6232 insertions(+), 15 deletions(-)

diff --git a/configure b/configure
index db691a6..33a7413 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for xsp 4.0.
+# Generated by GNU Autoconf 2.69 for xsp 4.2.
 #
 # Report bugs to <http://bugzilla.xamarin.com/>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='xsp'
 PACKAGE_TARNAME='xsp'
-PACKAGE_VERSION='4.0'
-PACKAGE_STRING='xsp 4.0'
+PACKAGE_VERSION='4.2'
+PACKAGE_STRING='xsp 4.2'
 PACKAGE_BUGREPORT='http://bugzilla.xamarin.com/'
 PACKAGE_URL=''
 
@@ -1373,7 +1373,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures xsp 4.0 to adapt to many kinds of systems.
+\`configure' configures xsp 4.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1444,7 +1444,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of xsp 4.0:";;
+     short | recursive ) echo "Configuration of xsp 4.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1566,7 +1566,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-xsp configure 4.0
+xsp configure 4.2
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1844,7 +1844,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by xsp $as_me 4.0, which was
+It was created by xsp $as_me 4.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2819,7 +2819,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='xsp'
- VERSION='4.0'
+ VERSION='4.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -12967,7 +12967,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by xsp $as_me 4.0, which was
+This file was extended by xsp $as_me 4.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -13024,7 +13024,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-xsp config.status 4.0
+xsp config.status 4.2
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index ad9be55..29b990f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.53])
-AC_INIT([xsp], [4.0], [http://bugzilla.xamarin.com/])
+AC_INIT([xsp], [4.2], [http://bugzilla.xamarin.com/])
 AC_CANONICAL_SYSTEM
 AC_CONFIG_MACRO_DIR([build/m4])
 AM_INIT_AUTOMAKE([foreign])
diff --git a/src/Mono.WebServer.XSP/Makefile.am b/src/Mono.WebServer.XSP/Makefile.am
index 1584803..2514380 100644
--- a/src/Mono.WebServer.XSP/Makefile.am
+++ b/src/Mono.WebServer.XSP/Makefile.am
@@ -20,7 +20,7 @@ pkgconfig_DATA += xsp-4.pc
 sources = $(shell cat $(srcdir)/Mono.WebServer.XSP.sources)
 build_sources = $(addprefix $(srcdir)/, $(sources)) AssemblyInfo.cs
 
-EXTRA_DIST = $(sources) AssemblyInfo.cs.in
+EXTRA_DIST = $(sources) Mono.WebServer.XSP.sources AssemblyInfo.cs.in
 
 xsp4.exe: $(build_sources)
 	$(DMCS) -d:NET_2_0 -d:NET_4_0 $(MCSFLAGS) $(references4) /out:$@ $(build_sources)
diff --git a/src/Mono.WebServer.XSP/Makefile.in b/src/Mono.WebServer.XSP/Makefile.in
index a5316df..d2702c5 100644
--- a/src/Mono.WebServer.XSP/Makefile.in
+++ b/src/Mono.WebServer.XSP/Makefile.in
@@ -320,7 +320,7 @@ references4 = $(references_common) -r:../Mono.WebServer/4.0/Mono.WebServer2.dll
 pkgconfig_DATA = xsp-2.pc xsp-4.pc
 sources = $(shell cat $(srcdir)/Mono.WebServer.XSP.sources)
 build_sources = $(addprefix $(srcdir)/, $(sources)) AssemblyInfo.cs
-EXTRA_DIST = $(sources) AssemblyInfo.cs.in
+EXTRA_DIST = $(sources) Mono.WebServer.XSP.sources AssemblyInfo.cs.in
 all: all-am
 
 .SUFFIXES:
diff --git a/src/Mono.WebServer.XSP/Mono.WebServer.XSP.sources b/src/Mono.WebServer.XSP/Mono.WebServer.XSP.sources
new file mode 100644
index 0000000..855ad43
--- /dev/null
+++ b/src/Mono.WebServer.XSP/Mono.WebServer.XSP.sources
@@ -0,0 +1,10 @@
+./CompatTuple.cs
+./ConfigurationManager.cs
+./main.cs
+./SecurityConfiguration.cs
+./SslInformation.cs
+./XSPApplicationHost.cs
+./XSPRequestBroker.cs
+./XSPWebSource.cs
+./XSPWorker.cs
+./XSPWorkerRequest.cs
diff --git a/src/Mono.WebServer/ApplicationServer.cs b/src/Mono.WebServer/ApplicationServer.cs
new file mode 100644
index 0000000..df8e315
--- /dev/null
+++ b/src/Mono.WebServer/ApplicationServer.cs
@@ -0,0 +1,551 @@
+//
+// ApplicationServer.cs
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// Copyright (c) Copyright 2002-2007 Novell, Inc
+//
+// 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.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+using System.Xml;
+using System.Text;
+using System.Threading;
+using System.IO;
+using Mono.WebServer.Log;
+
+namespace Mono.WebServer
+{
+	// ApplicationServer runs the main server thread, which accepts client 
+	// connections and forwards the requests to the correct web application.
+	// ApplicationServer takes an WebSource object as parameter in the 
+	// constructor. WebSource provides methods for getting some objects
+	// whose behavior is specific to XSP or mod_mono.
+	
+	// Each web application lives in its own application domain, and incoming
+	// requests are processed in the corresponding application domain.
+	// Since the client Socket can't be passed from one domain to the other, the
+	// flow of information must go through the cross-app domain channel.
+	 
+	// For each application two objects are created:
+	// 1) a IApplicationHost object is created in the application domain
+	// 2) a IRequestBroker is created in the main domain.
+	//
+	// The IApplicationHost is used by the ApplicationServer to start the
+	// processing of a request in the application domain.
+	// The IRequestBroker is used from the application domain to access 
+	// information in the main domain.
+	//
+	// The complete sequence of servicing a request is the following:
+	//
+	// 1) The listener accepts an incoming connection.
+	// 2) An Worker object is created (through the WebSource), and it is
+	//    queued in the thread pool.
+	// 3) When the Worker's run method is called, it registers itself in
+	//    the application's request broker, and gets a request id. All this is
+	//    done in the main domain.
+	// 4) The Worker starts the request processing by making a cross-app domain
+	//    call to the application host. It passes as parameters the request id
+	//    and other information already read from the request.
+	// 5) The application host executes the request. When it needs to read or
+	//    write request data, it performs remote calls to the request broker,
+	//    passing the request id provided by the Worker.
+	// 6) When the request broker receives a call from the application host,
+	//    it locates the Worker registered with the provided request id and
+	//    forwards the call to it.
+	
+	public class ApplicationServer : MarshalByRefObject
+	{
+		readonly WebSource webSource;
+		bool started;
+		bool stop;
+		Socket listen_socket;
+
+		Thread runner;
+
+		// This is much faster than hashtable for typical cases.
+		readonly List<VPathToHost> vpathToHost = new List<VPathToHost> ();
+
+		public bool SingleApplication { get; set; }
+
+		public IApplicationHost AppHost {
+			get { return vpathToHost [0].AppHost; }
+			set { vpathToHost [0].AppHost = value; }
+		}
+
+		public IRequestBroker Broker {
+			get { return vpathToHost [0].RequestBroker; }
+			set { vpathToHost [0].RequestBroker = value; }
+		}
+
+		public int Port {
+			get {
+				if (listen_socket == null || !listen_socket.IsBound)
+					return -1;
+
+				var iep = listen_socket.LocalEndPoint as IPEndPoint;
+				if (iep == null)
+					return -1;
+
+				return iep.Port;
+			}
+		}
+
+		public string PhysicalRoot { get; private set; }
+
+		public bool Verbose { get; set; }
+
+		[Obsolete ("Use the .ctor that takes a 'physicalRoot' argument instead")]
+		public ApplicationServer (WebSource source) : this (source, Environment.CurrentDirectory)
+		{
+		}
+
+		public ApplicationServer (WebSource source, string physicalRoot)
+		{
+			if (source == null)
+				throw new ArgumentNullException ("source");
+			if (String.IsNullOrEmpty (physicalRoot))
+				throw new ArgumentNullException ("physicalRoot");
+			
+			webSource = source;
+			PhysicalRoot = physicalRoot;
+		}
+
+		public void AddApplication (string vhost, int vport, string vpath, string fullPath)
+		{
+			char dirSepChar = Path.DirectorySeparatorChar;
+			if (fullPath != null && !fullPath.EndsWith (dirSepChar.ToString ()))
+				fullPath += dirSepChar;
+			
+			// TODO: Check for duplicates, sort, optimize, etc.
+			if (Verbose && !SingleApplication) {
+				Logger.Write (LogLevel.Notice, "Registering application:");
+				Logger.Write(LogLevel.Notice, "    Host:          {0}", vhost ?? "any");
+				Logger.Write(LogLevel.Notice, "    Port:          {0}", (vport != -1) ? vport.ToString () : "any");
+
+				Logger.Write(LogLevel.Notice, "    Virtual path:  {0}", vpath);
+				Logger.Write(LogLevel.Notice, "    Physical path: {0}", fullPath);
+			}
+
+			vpathToHost.Add (new VPathToHost (vhost, vport, vpath, fullPath));
+		}
+
+ 		public void AddApplicationsFromConfigDirectory (string directoryName)
+ 		{
+			if (Verbose && !SingleApplication) {
+				Logger.Write(LogLevel.Notice, "Adding applications from *.webapp files in directory '{0}'", directoryName);
+			}
+
+			var di = new DirectoryInfo (directoryName);
+			if (!di.Exists) {
+				Logger.Write (LogLevel.Error, "Directory {0} does not exist.", directoryName);
+				return;
+			}
+			
+			foreach (FileInfo fi in di.GetFiles ("*.webapp"))
+				AddApplicationsFromConfigFile (fi.FullName);
+		}
+
+ 		public void AddApplicationsFromConfigFile (string fileName)
+ 		{
+			if (Verbose && !SingleApplication) {
+				Logger.Write(LogLevel.Notice, "Adding applications from config file '{0}'", fileName);
+			}
+
+			try {
+				var doc = new XmlDocument ();
+				doc.Load (fileName);
+
+				foreach (XmlElement el in doc.SelectNodes ("//web-application")) {
+					AddApplicationFromElement (el);
+				}
+			} catch {
+				Logger.Write(LogLevel.Error, "Error loading '{0}'", fileName);
+				throw;
+			}
+		}
+
+		void AddApplicationFromElement (XmlNode el)
+		{
+			XmlNode n = el.SelectSingleNode ("enabled");
+			if (n != null && n.InnerText.Trim () == "false")
+				return;
+
+			string vpath = el.SelectSingleNode ("vpath").InnerText;
+			string path = el.SelectSingleNode ("path").InnerText;
+
+			string vhost = null;
+			n = el.SelectSingleNode ("vhost");
+#if !MOD_MONO_SERVER
+			if (n != null)
+				vhost = n.InnerText;
+#else
+			// TODO: support vhosts in xsp.exe
+			string name = el.SelectSingleNode ("name").InnerText;
+			if (verbose && !single_app)
+				Logger.Write (LogLevel.Warning, ("Ignoring vhost {0} for {1}", n.InnerText, name);
+#endif
+
+			int vport = -1;
+			n = el.SelectSingleNode ("vport");
+#if !MOD_MONO_SERVER
+			if (n != null)
+				vport = Convert.ToInt32 (n.InnerText);
+#else
+			// TODO: Listen on different ports
+			if (verbose && !single_app)
+				Logger.Write (LogLevel.Warning, ("Ignoring vport {0} for {1}", n.InnerText, name);
+#endif
+
+			AddApplication (vhost, vport, vpath, path);
+		}
+
+ 		public void AddApplicationsFromCommandLine (string applications)
+ 		{
+ 			if (applications == null)
+ 				throw new ArgumentNullException ("applications");
+ 
+			if (applications.Length == 0)
+				return;
+
+			if (Verbose && !SingleApplication) {
+				Logger.Write(LogLevel.Notice, "Adding applications '{0}'...", applications);
+			}
+
+ 			string [] apps = applications.Split (',');
+
+			foreach (string str in apps) {
+				string [] app = str.Split (':');
+
+				if (app.Length < 2 || app.Length > 4)
+					throw new ArgumentException ("Should be something like " +
+								     "[[hostname:]port:]VPath:realpath");
+
+				int vport;
+				int pos = 0;
+
+				string vhost = app.Length >= 3 ? app[pos++] : null;
+
+				if (app.Length >= 4) {
+					// FIXME: support more than one listen port.
+					vport = Convert.ToInt16 (app[pos++]);
+				} else {
+					vport = -1;
+				}
+
+				string vpath = app [pos++];
+				string realpath = app[pos++];
+
+				if (!vpath.EndsWith ("/"))
+					vpath += "/";
+ 
+ 				string fullPath = Path.GetFullPath (realpath);
+				AddApplication (vhost, vport, vpath, fullPath);
+ 			}
+ 		}
+
+		[Obsolete]
+		public bool Start (bool bgThread, Exception initialException, int backlog)
+		{
+			return Start (bgThread, backlog);
+		}
+		
+		public bool Start (bool bgThread, int backlog)
+		{
+			if (started)
+				throw new InvalidOperationException ("The server is already started.");
+
+ 			if (vpathToHost == null)
+ 				throw new InvalidOperationException ("SetApplications must be called first.");
+
+			if (SingleApplication) {
+				var v = vpathToHost [0];
+				v.AppHost = AppHost;
+				// Link the host in the application domain with a request broker in the *same* domain
+				// Not needed for SingleApplication and mod_mono
+				v.RequestBroker = webSource.CreateRequestBroker ();
+				AppHost.RequestBroker = v.RequestBroker;
+			}
+
+			listen_socket = webSource.CreateSocket ();
+			listen_socket.Listen (backlog);
+			runner = new Thread (RunServer) {IsBackground = bgThread};
+			runner.Start ();
+			stop = false;
+			return true;
+		}
+
+		public void Stop ()
+		{
+			if (!started)
+				throw new InvalidOperationException ("The server is not started.");
+
+			if (stop)
+				return; // Just ignore, as we're already stopping
+
+			stop = true;	
+			webSource.Dispose ();
+
+			// A foreground thread is required to end cleanly
+			var stopThread = new Thread (RealStop);
+			stopThread.Start ();
+		}
+
+		public void ShutdownSockets ()
+		{
+			if (listen_socket != null) {
+				try {
+					listen_socket.Close ();
+				} catch {
+				} finally {
+					listen_socket = null;
+				}
+			}
+		}
+
+		void RealStop ()
+		{
+			started = false;
+			runner.Abort ();
+			ShutdownSockets ();
+			UnloadAll ();
+		}
+
+		public void UnloadAll ()
+		{
+			lock (vpathToHost) {
+				foreach (VPathToHost v in vpathToHost) {
+					v.UnloadHost ();
+				}
+			}
+		}
+
+		void SetSocketOptions (Socket sock)
+		{
+
+			try {
+				sock.LingerState = new LingerOption (true, 15);
+#if !MOD_MONO_SERVER
+				sock.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 15000); // 15s
+				sock.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 15000); // 15s
+#endif
+			} catch {
+				// Ignore exceptions here for systems that do not support these options.
+			}
+		}
+
+		void RunServer ()
+		{
+			started = true;
+			var args = new SocketAsyncEventArgs ();
+			args.Completed += OnAccept;
+			listen_socket.AcceptAsync (args);
+			if (runner.IsBackground)
+				return;
+
+			while (true) // Just sleep until we're aborted.
+				Thread.Sleep (1000000);
+		}
+
+		void OnAccept (object sender, SocketAsyncEventArgs e)
+		{
+			if (!started && SingleApplication) {
+				// We are shutting down. Last call...
+				Environment.Exit (0);
+			}
+
+			Socket accepted = e.AcceptSocket;
+			e.AcceptSocket = null;
+
+			if (e.SocketError != SocketError.Success) {
+				CloseSocket(accepted);
+				accepted = null;
+			}
+
+			try {
+				if (started)
+					listen_socket.AcceptAsync (e);
+			} catch (Exception ex) {
+				if (accepted != null)
+					CloseSocket (accepted);
+
+				// not much we can do. fast fail by killing the process.
+				Logger.Write (LogLevel.Error, "Unable to accept socket. Exiting the process. {0}", ex);
+				Environment.Exit (1);
+			}
+
+			if (accepted == null)
+				return;
+
+			SetSocketOptions (accepted);
+			StartRequest (accepted, 0);
+		}
+
+		void CloseSocket(Socket socket)
+		{
+			if (socket == null)
+				return;
+
+			// attempt a quick RST of the connection
+			try {
+				socket.LingerState = new LingerOption (true, 0);
+			} catch {
+				// ignore
+			}
+
+			try {
+				socket.Close();
+			} catch {
+				// ignore
+			}
+		}
+
+		void SendException (Socket socket, Exception ex)
+		{
+			var sb = new StringBuilder ();
+			string now = DateTime.Now.ToUniversalTime ().ToString ("r");
+
+			sb.Append ("HTTP/1.0 500 Server error\r\n");
+			sb.AppendFormat ("Date: {0}\r\n" +
+					 "Expires: {0}\r\n" +
+					 "Last-Modified: {0}\r\n", now);
+			sb.AppendFormat ("Expires; {0}\r\n", now);
+			sb.Append ("Cache-Control: private, must-revalidate, max-age=0\r\n");
+			sb.Append ("Content-Type: text/html; charset=UTF-8\r\n");
+			sb.Append ("Connection: close\r\n\r\n");
+			
+			sb.AppendFormat ("<html><head><title>Exception: {0}</title></head><body>" +
+					 "<h1>Exception caught.</h1>" +
+					 "<pre>{0}</pre>" +
+					 "</body></html>", ex);
+
+			byte[] data = Encoding.UTF8.GetBytes (sb.ToString ());
+			try {
+				int sent = socket.Send (data);
+				if (sent != data.Length)
+					throw new IOException ("Blocking send did not send entire buffer");
+			} catch (Exception ex2) {
+				Logger.Write(LogLevel.Error, "Failed to send exception:");
+				Logger.Write(ex);
+				Logger.Write(LogLevel.Error, "Exception ocurred while sending:");
+				Logger.Write(ex2);
+			}	
+		}
+		
+		void StartRequest (Socket accepted, int reuses)
+		{
+			try {
+				// The next line can throw (reusing and the client closed)
+				Worker worker = webSource.CreateWorker (accepted, this);
+				worker.SetReuseCount (reuses);
+				if (worker.IsAsync)
+					worker.Run (null);
+				else
+					ThreadPool.QueueUserWorkItem (worker.Run);
+			} catch (Exception) {
+				try {
+					if (accepted != null) {
+						try {
+							if (accepted.Connected)
+								accepted.Shutdown (SocketShutdown.Both);
+						} catch {
+							// ignore
+						}
+						
+						accepted.Close ();
+					}
+				} catch {
+					// ignore
+				}
+			}
+		}
+
+		public void ReuseSocket (Socket sock, int reuses)
+		{
+			StartRequest (sock, reuses);
+		}
+
+		public VPathToHost GetApplicationForPath (string vhost, int port, string path,
+							  bool defaultToRoot)
+		{
+			if (SingleApplication)
+				return vpathToHost [0];
+
+			VPathToHost bestMatch = null;
+			int bestMatchLength = 0;
+
+			for (int i = vpathToHost.Count - 1; i >= 0; i--) {
+				var v = vpathToHost [i];
+				int matchLength = v.vpath.Length;
+				if (matchLength <= bestMatchLength || !v.Match (vhost, port, path))
+					continue;
+
+				bestMatchLength = matchLength;
+				bestMatch = v;
+			}
+
+			if (bestMatch != null) {
+				lock (bestMatch) {
+					if (bestMatch.AppHost == null)
+						bestMatch.CreateHost (this, webSource);
+				}
+				return bestMatch;
+			}
+			
+			if (defaultToRoot)
+				return GetApplicationForPath (vhost, port, "/", false);
+
+			if (Verbose)
+				Logger.Write(LogLevel.Error, "No application defined for: {0}:{1}{2}", vhost, port, path);
+
+			return null;
+		}
+
+		public VPathToHost GetSingleApp ()
+		{
+			if (vpathToHost.Count == 1)
+				return vpathToHost [0];
+			return null;
+		}
+
+		public void DestroyHost (IApplicationHost host)
+		{
+			// Called when the host appdomain is being unloaded
+			for (int i = vpathToHost.Count - 1; i >= 0; i--) {
+				var v = vpathToHost [i];
+				if (v.TryClearHost (host))
+					break;
+			}
+		}
+
+		public override object InitializeLifetimeService ()
+		{
+			return null;
+		}
+	}
+}
+
diff --git a/src/Mono.WebServer/BaseApplicationHost.cs b/src/Mono.WebServer/BaseApplicationHost.cs
new file mode 100644
index 0000000..21c8b3b
--- /dev/null
+++ b/src/Mono.WebServer/BaseApplicationHost.cs
@@ -0,0 +1,273 @@
+// Mono.WebServer.BaseApplicationHost
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// (C) Copyright 2004 Novell, Inc
+//
+// 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.IO.Foo;
+using System.Threading;
+using System.Web;
+using System.Web.Configuration;
+using System.Collections.Generic;
+using Mono.WebServer.Log;
+
+namespace Mono.WebServer
+{
+	public class BaseApplicationHost : MarshalByRefObject, IApplicationHost
+	{
+		static readonly ReaderWriterLockSlim handlersCacheLock = new ReaderWriterLockSlim ();
+		
+		string path;
+		string vpath;
+		readonly EndOfRequestHandler endOfRequest;
+		Dictionary <string, bool> handlersCache;		
+
+		public BaseApplicationHost ()
+		{
+			endOfRequest = EndOfRequest;
+			AppDomain.CurrentDomain.DomainUnload += OnUnload;
+		}
+
+		public void Unload ()
+		{
+			HttpRuntime.UnloadAppDomain ();
+		}
+
+		public void OnUnload (object o, EventArgs args)
+		{
+			if (Server != null)
+				Server.DestroyHost (this);
+		}
+
+		public override object InitializeLifetimeService ()
+		{
+			return null; // who wants to live forever?
+		}
+
+		public ApplicationServer Server { get; set; }
+
+		public string Path {
+			get {
+				if (path == null)
+					path = AppDomain.CurrentDomain.GetData (".appPath").ToString ();
+
+				return path;
+			}
+		}
+
+		public string VPath {
+			get {
+				if (vpath == null)
+					vpath = AppDomain.CurrentDomain.GetData (".appVPath").ToString ();
+
+				return vpath;
+			}
+		}
+
+		public AppDomain Domain {
+			get { return AppDomain.CurrentDomain; }
+		}
+
+		public IRequestBroker RequestBroker { get; set; }
+
+		protected void ProcessRequest (MonoWorkerRequest mwr)
+		{
+			if (mwr == null)
+				throw new ArgumentNullException ("mwr");
+			
+			if (!mwr.ReadRequestData ()) {
+				EndOfRequest (mwr);
+				return;
+			}
+			
+			mwr.EndOfRequestEvent += endOfRequest;
+			try {
+				mwr.ProcessRequest ();
+			} catch (ThreadAbortException) {
+				Thread.ResetAbort ();
+			} catch (Exception ex) { // should "never" happen
+				// we don't know what the request state is,
+				// better write the exception to the console
+				// than forget it.
+				Logger.Write(LogLevel.Error, "Unhandled exception: {0}", ex);
+				EndOfRequest (mwr);
+			}
+		}
+
+		public void EndOfRequest (MonoWorkerRequest mwr)
+		{
+			try {
+				mwr.CloseConnection ();
+			} catch {
+			} finally {
+				var brb = RequestBroker as BaseRequestBroker;
+				if (brb != null)
+					brb.UnregisterRequest (mwr.RequestId);
+			}
+		}
+
+		public virtual bool IsHttpHandler (string verb, string uri)
+		{
+			string cacheKey = verb + "_" + uri;
+
+			bool locked = false;
+			try {
+				handlersCacheLock.EnterReadLock ();
+
+				locked = true;
+				if (handlersCache != null) {
+					bool found;
+					if (handlersCache.TryGetValue (cacheKey, out found))
+						return found;
+				} else {
+					handlersCache = new Dictionary <string, bool> ();
+				}
+			} finally {
+				if (locked)
+					handlersCacheLock.ExitReadLock ();
+			}
+			
+			
+			bool handlerFound = LocateHandler (verb, uri);
+			locked = false;
+			try {
+				handlersCacheLock.EnterWriteLock ();
+
+				locked = true;
+				if (handlersCache.ContainsKey (cacheKey))
+					handlersCache [cacheKey] = handlerFound;
+				else
+					handlersCache.Add (cacheKey, handlerFound);
+			} finally {
+				if (locked)
+					handlersCacheLock.ExitWriteLock ();
+			}
+			
+			return handlerFound;
+		}
+
+		bool LocateHandler (string verb, string uri)
+		{
+			var config = WebConfigurationManager.GetSection ("system.web/httpHandlers") as HttpHandlersSection;
+			HttpHandlerActionCollection handlers = config != null ? config.Handlers : null;
+			int count = handlers != null ? handlers.Count : 0;
+			
+			if (count == 0)
+				return false;
+
+			for (int i = 0; i < count; i++) {
+				HttpHandlerAction handler = handlers [i];
+				string[] verbs = SplitVerbs (handler.Verb);
+
+				if (verbs == null) {
+					if (PathMatches (handler, uri))
+						return true;
+					continue;
+				}
+
+				for (int j = 0; j < verbs.Length; j++) {
+					if (verbs [j] != verb)
+						continue;
+					if (PathMatches (handler, uri))
+						return true;
+				}
+			}
+
+			return false;
+		}
+
+		bool PathMatches (HttpHandlerAction handler, string uri)
+		{
+			bool result = false;
+			string[] handlerPaths = handler.Path.Split (',');
+			int slash = uri.LastIndexOf ('/');
+			string origUri = uri;
+			if (slash != -1)
+				uri = uri.Substring (slash);
+
+			SearchPattern sp = null;
+			foreach (string handlerPath in handlerPaths) {
+				if (handlerPath == "*")
+					continue; // ignore
+				
+				string matchExact = null;
+				string endsWith = null;
+
+				if (handlerPath.Length > 0) {
+					if (handlerPath [0] == '*' && (handlerPath.IndexOf ('*', 1) == -1))
+						endsWith = handlerPath.Substring (1);
+
+					if (handlerPath.IndexOf ('*') == -1)
+					if (handlerPath [0] != '/') {
+						string vpath = HttpRuntime.AppDomainAppVirtualPath;
+
+						if (vpath == "/")
+							vpath = String.Empty;
+
+						matchExact = String.Concat (vpath, "/", handlerPath);
+					}
+				}
+
+				if (matchExact != null) {
+					result = matchExact.Length == origUri.Length && origUri.EndsWith (matchExact, StringComparison.OrdinalIgnoreCase);
+					if (result)
+						break;
+					continue;
+				}
+				if (endsWith != null) {
+					result = uri.EndsWith (endsWith, StringComparison.OrdinalIgnoreCase);
+					if (result)
+						break;
+					continue;
+				}
+
+				string pattern;
+				if (handlerPath.Length > 0 && handlerPath [0] == '/')
+					pattern = handlerPath.Substring (1);
+				else
+					pattern = handlerPath;
+
+				if (sp == null)
+					sp = new SearchPattern (pattern, true);
+				else
+					sp.SetPattern (pattern, true);
+				
+				if (sp.IsMatch (origUri)) {
+					result = true;
+					break;
+				}
+			}
+			
+			return result;
+		}
+
+		static string[] SplitVerbs (string verb)
+		{
+			return verb == "*" ? null : verb.Split (',');
+		}
+	}
+}
+
diff --git a/src/Mono.WebServer/BaseRequestBroker.cs b/src/Mono.WebServer/BaseRequestBroker.cs
new file mode 100644
index 0000000..70602d7
--- /dev/null
+++ b/src/Mono.WebServer/BaseRequestBroker.cs
@@ -0,0 +1,268 @@
+//
+// Mono.WebServer.BaseRequestBroker
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+// 	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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;
+
+namespace Mono.WebServer
+{
+	public class BaseRequestBroker: MarshalByRefObject, IRequestBroker
+	{
+		public event UnregisterRequestEventHandler UnregisterRequestEvent;
+		
+		//  Contains the initial request capacity of a BaseRequestBroker
+		const int INITIAL_REQUESTS = 200;
+
+		//  The size of a request buffer in bytes.
+		//
+		//  This number should be equal to INPUT_BUFFER_SIZE
+		//  in System.Web.HttpRequest.
+		const int BUFFER_SIZE = 32*1024;
+		
+		// Contains a lock to use when accessing and modifying the
+		// request allocation tables.
+		static readonly object reqlock = new object();
+
+		// Contains the request ID's.
+		int[] request_ids = new int [INITIAL_REQUESTS];
+
+		// Contains the registered workers.
+		Worker[] requests = new Worker [INITIAL_REQUESTS];
+		
+		// Contains buffers for the requests to use.
+		byte[][] buffers = new byte [INITIAL_REQUESTS][];
+		
+		// Contains the number of active requests.
+		int requests_count;
+
+		// Contains the total number of requests served so far.
+		// May freely wrap around.
+		uint requests_served;
+
+		/// <summary>
+		/// Grows the size of the request allocation tables by 33%.
+		///
+		/// This *MUST* be called with the reqlock held!
+		/// </summary>
+		/// <returns>ID to use for a new request.</returns>
+		/// <param name="curlen">Current length of the allocation tables.</param>
+		int GrowRequests (ref int curlen)
+		{
+			int newsize = curlen + curlen/3;
+			var new_request_ids = new int [newsize];
+			var new_requests = new Worker [newsize];
+			var new_buffers = new byte [newsize][];
+
+			request_ids.CopyTo (new_request_ids, 0);
+			Array.Clear (request_ids, 0, request_ids.Length);
+			request_ids = new_request_ids;
+			
+			requests.CopyTo (new_requests, 0);
+			Array.Clear (requests, 0, requests.Length);
+			requests = new_requests;
+			
+			buffers.CopyTo (new_buffers, 0);
+			Array.Clear (buffers, 0, buffers.Length);
+			buffers = new_buffers;
+
+			curlen = newsize;
+			return curlen + 1;
+		}
+		
+		/// <summary>
+		/// Gets the next available request ID, expanding the array
+		/// of possible ID's if necessary.
+		///
+		/// This *MUST* be called with the reqlock held!
+		/// </summary>
+		/// <returns>ID of the request.</returns>
+		int GetNextRequestId ()
+		{
+			int reqlen = request_ids.Length;
+
+			requests_served++; // increment to 1 before putting into request_ids
+					   // so that the 0 id is reserved for slot not used
+			if (requests_served == 0x8000) // and check for wrap-around for the above
+				requests_served = 1; // making sure we don't exceed 0x7FFF or go negative
+
+			requests_count++;
+
+			int newid;
+			if (requests_count >= reqlen)
+				newid = GrowRequests (ref reqlen);
+			else
+				newid = Array.IndexOf (request_ids, 0);
+
+			if (newid == -1) {
+				// Should never happen...
+				throw new ApplicationException ("could not allocate new request id");
+			}
+
+			// TODO: newid had better not exceed 0xFFFF.
+			newid = ((ushort)newid & 0xFFFF) | (((ushort)requests_served & 0x7FFF) << 16);
+			request_ids [IdToIndex(newid)] = newid;
+			return newid;
+		}		
+
+		public int RegisterRequest (Worker worker)
+		{
+			int result;
+			
+			lock (reqlock) {
+				result = IdToIndex (GetNextRequestId ());
+				requests [result] = worker;
+				
+				// Don't create a new array if one already exists.
+				byte[] a = buffers [result];
+				if (a == null)
+					buffers [result] = new byte [BUFFER_SIZE];
+			}
+
+			return request_ids [result];
+		}
+
+		int IdToIndex(int requestId) {
+			return requestId & 0xFFFF;
+		}
+
+		public void UnregisterRequest (int id)
+		{
+			lock (reqlock) {
+				if (!ValidRequest (id))
+					return;
+				
+				DoUnregisterRequest (id);
+				int idx = IdToIndex (id);
+
+				byte[] a = buffers [idx];
+				if (a != null)
+					Array.Clear (a, 0, a.Length);
+				requests [idx] = null;
+				request_ids [idx] = 0;
+				requests_count--;
+			}
+		}
+
+		/// <summary>
+		/// Invokes registered handlers of UnregisterRequestEvent. Each handler is passed an
+		/// arguments object which contains the ID of a request that is about to be
+		/// unregistered.
+		/// </summary>
+		/// <param name="id">ID of a request that is about to be unregistered.</param>
+		void DoUnregisterRequest (int id)
+		{
+			if (UnregisterRequestEvent == null)
+				return;
+			Delegate[] handlers = UnregisterRequestEvent.GetInvocationList ();
+			if (handlers == null || handlers.Length == 0)
+				return;
+			
+			var args = new UnregisterRequestEventArgs (id);
+			foreach (UnregisterRequestEventHandler handler in handlers)
+				handler (this, args);
+		}		
+
+		protected bool ValidRequest (int requestId)
+		{
+			int idx = IdToIndex (requestId);
+			return (idx >= 0 && idx < request_ids.Length && request_ids [idx] == requestId &&
+				buffers [idx] != null);
+		}		
+
+		public int Read (int requestId, int size, out byte[] buffer)
+		{
+			buffer = null;
+			
+			Worker w;
+
+			lock (reqlock) {
+				if (!ValidRequest (requestId))
+					return 0;
+
+				w = GetWorker (requestId);
+				if (w == null)
+					return 0;
+
+				// Use a pre-allocated buffer only when the size matches
+				// as it will be transferred across appdomain boundaries
+				// in full length
+				if (size == BUFFER_SIZE) {
+					buffer = buffers [IdToIndex (requestId)];
+				} else {
+					buffer = new byte[size];
+				}
+			}
+
+			return w.Read (buffer, 0, size);
+		}		
+
+		public Worker GetWorker (int requestId)
+		{
+			lock (reqlock) {
+				if (!ValidRequest (requestId))
+					return null;
+			
+				return requests [IdToIndex (requestId)];
+			}
+		}
+
+		public void Write (int requestId, byte[] buffer, int position, int size)
+		{
+			Worker worker = GetWorker (requestId);
+			if (worker != null)
+				worker.Write (buffer, position, size);
+		}		
+
+		public void Close (int requestId)
+		{
+			Worker worker = GetWorker (requestId);
+			if (worker != null)
+				worker.Close ();
+		}		
+
+		public void Flush (int requestId)
+		{
+			Worker worker = GetWorker (requestId);
+			if (worker != null)
+				worker.Flush ();
+		}
+
+		public bool IsConnected (int requestId)
+		{
+			Worker worker = GetWorker (requestId);
+			
+			return (worker != null && worker.IsConnected ());
+		}
+		
+		public override object InitializeLifetimeService ()
+		{
+			return null;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/EndOfRequestHandler.cs b/src/Mono.WebServer/EndOfRequestHandler.cs
new file mode 100644
index 0000000..59dd1a6
--- /dev/null
+++ b/src/Mono.WebServer/EndOfRequestHandler.cs
@@ -0,0 +1,39 @@
+//
+// Mono.WebServer.EndOfRequestHandler
+//
+// Authors:
+//	Daniel Lopez Ridruejo
+// 	Gonzalo Paniagua Javier
+//
+// Documentation:
+//	Brian Nickel
+//
+// Copyright (c) 2002 Daniel Lopez Ridruejo.
+//           (c) 2002,2003 Ximian, Inc.
+//           All rights reserved.
+// (C) Copyright 2004-2010 Novell, Inc. (http://www.novell.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.
+//
+
+namespace Mono.WebServer
+{
+	public delegate void EndOfRequestHandler (MonoWorkerRequest request);
+}
diff --git a/src/Mono.WebServer/FinePlatformID.cs b/src/Mono.WebServer/FinePlatformID.cs
new file mode 100644
index 0000000..bc4b064
--- /dev/null
+++ b/src/Mono.WebServer/FinePlatformID.cs
@@ -0,0 +1,35 @@
+//
+// FinePlatformID.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.
+//
+
+namespace Mono.WebServer {
+	public enum FinePlatformID {
+		Windows,
+		Linux,
+		MacOSX
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/HttpErrors.cs b/src/Mono.WebServer/HttpErrors.cs
new file mode 100644
index 0000000..93bfefc
--- /dev/null
+++ b/src/Mono.WebServer/HttpErrors.cs
@@ -0,0 +1,80 @@
+//
+// HttpErrors.cs
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// Copyright (c) Copyright 2002-2007 Novell, Inc
+//
+// 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.Text;
+
+namespace Mono.WebServer
+{
+	public class HttpErrors
+	{
+		static readonly byte [] error500;
+		static readonly byte [] badRequest;
+
+		static HttpErrors ()
+		{
+			const string s = "HTTP/1.0 500 Server error\r\n" +
+				"Connection: close\r\n\r\n" +
+				"<html><head><title>500 Server Error</title><body><h1>Server error</h1>\r\n" +
+				"Your client sent a request that was not understood by this server.\r\n" +
+				"</body></html>\r\n";
+			error500 = Encoding.ASCII.GetBytes (s);
+
+			const string br = "HTTP/1.0 400 Bad Request\r\n" + 
+				"Connection: close\r\n\r\n" +
+				"<html><head><title>400 Bad Request</title></head>" +
+				"<body><h1>Bad Request</h1>The request was not understood" +
+				"<p></body></html>";
+
+			badRequest = Encoding.ASCII.GetBytes (br);
+		}
+
+		public static byte [] NotFound (string uri)
+		{
+			string s = String.Format ("HTTP/1.0 404 Not Found\r\n" + 
+						  "Connection: close\r\n\r\n" +
+						  "<html><head><title>404 Not Found</title></head>\r\n" +
+						  "<body><h1>Not Found</h1>The requested URL {0} was not found on this " +
+						  "server.<p>\r\n</body></html>\r\n", uri);
+
+			return Encoding.ASCII.GetBytes (s);
+		}
+
+		public static byte [] BadRequest ()
+		{
+			return badRequest;
+		}
+
+		public static byte [] ServerError ()
+		{
+			return error500;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/IApplicationHost.cs b/src/Mono.WebServer/IApplicationHost.cs
new file mode 100644
index 0000000..3e6db1b
--- /dev/null
+++ b/src/Mono.WebServer/IApplicationHost.cs
@@ -0,0 +1,48 @@
+//
+// Mono.WebServer.IApplicationHost
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//
+// Documentation:
+//	Brian Nickel
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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;
+
+namespace Mono.WebServer
+{
+	public interface IApplicationHost
+	{
+		string Path { get; }
+		string VPath { get; }
+		AppDomain Domain { get; }
+		IRequestBroker RequestBroker { get; set; }
+		ApplicationServer Server { get; set; }
+		void Unload ();
+		bool IsHttpHandler (string verb, string uri);
+	}
+}
diff --git a/src/Mono.WebServer/IRequestBroker.cs b/src/Mono.WebServer/IRequestBroker.cs
new file mode 100644
index 0000000..834bde1
--- /dev/null
+++ b/src/Mono.WebServer/IRequestBroker.cs
@@ -0,0 +1,38 @@
+//
+// Mono.WebServer.IRequestBroker
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//
+// Documentation:
+//	Brian Nickel
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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.
+//
+
+namespace Mono.WebServer
+{
+	public interface IRequestBroker
+	{
+	}
+}
diff --git a/src/Mono.WebServer/IdentityToken.cs b/src/Mono.WebServer/IdentityToken.cs
new file mode 100644
index 0000000..400d069
--- /dev/null
+++ b/src/Mono.WebServer/IdentityToken.cs
@@ -0,0 +1,51 @@
+//
+// IdentityToken.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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 Mono.Unix.Native;
+
+namespace Mono.WebServer
+{
+	public class IdentityToken : IDisposable
+	{
+		readonly uint euid;
+		readonly uint egid;
+
+		public IdentityToken (uint euid, uint egid)
+		{
+			this.euid = euid;
+			this.egid = egid;
+		}
+
+		public void Dispose ()
+		{
+			Syscall.seteuid (euid);
+			Syscall.setegid (egid);
+		}
+	}
+}
diff --git a/src/Mono.WebServer/InitialWorkerRequest.cs b/src/Mono.WebServer/InitialWorkerRequest.cs
new file mode 100644
index 0000000..d3f7336
--- /dev/null
+++ b/src/Mono.WebServer/InitialWorkerRequest.cs
@@ -0,0 +1,281 @@
+//
+// Mono.WebServer.InitialWorkerRequest
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Web;
+
+namespace Mono.WebServer
+{
+	public class InitialWorkerRequest
+	{
+		string verb;
+		string path;
+		string queryString;
+		string protocol;
+		readonly Stream stream;
+
+		int inputLength;
+		int position;
+		const int B_SIZE = 1024 * 32;
+		
+		static readonly Stack<byte[]> bufferStack = new Stack<byte[]> ();
+		static readonly Encoding encoding = Encoding.GetEncoding (28591);
+
+		public bool GotSomeInput { get; private set; }
+
+		public byte [] InputBuffer { get; private set; }
+
+		public RequestData RequestData {
+			get {
+				var rd = new RequestData (verb, path, queryString, protocol);
+				var buffer = new byte [inputLength - position];
+				Buffer.BlockCopy (InputBuffer, position, buffer, 0, inputLength - position);
+				rd.InputBuffer = buffer;
+				return rd;
+			}
+		}
+		
+		public static byte [] AllocateBuffer ()
+		{
+			lock (bufferStack) {
+				if (bufferStack.Count != 0)
+					return bufferStack.Pop ();
+			}
+			return new byte [B_SIZE];
+		}
+		
+		public static void FreeBuffer (byte [] buf)
+		{
+			if (buf == null)
+				return;
+
+			lock (bufferStack) {
+				bufferStack.Push (buf);
+			}
+		}
+		
+		public InitialWorkerRequest (Stream ns)
+		{
+			if (ns == null)
+				throw new ArgumentNullException ("ns");
+
+			stream = ns;
+		}
+
+		public void FreeBuffer ()
+		{
+			if (InputBuffer != null)
+				FreeBuffer (InputBuffer);
+		}
+
+		public void SetBuffer (byte [] buffer, int length)
+		{
+			InputBuffer = buffer;
+			inputLength = length;
+			GotSomeInput = (length > 0);
+			position = 0;
+		}
+
+		void FillBuffer ()
+		{
+			position = 0;
+			InputBuffer = AllocateBuffer ();
+			inputLength = stream.Read (InputBuffer, 0, B_SIZE);
+			if (inputLength == 0) // Socket closed
+				throw new IOException ("socket closed");
+
+			GotSomeInput = true;
+		}
+
+		string ReadRequestLine ()
+		{
+			var text = new StringBuilder ();
+			do {
+				if (InputBuffer == null || position >= inputLength)
+					FillBuffer ();
+
+				if (position >= inputLength)
+					break;
+				
+				bool cr = false;
+				int count = 0;
+				byte b = 0;
+				int i;
+				for (i = position; count < 8192 && i < inputLength; i++, count++) {
+					b = InputBuffer [i];
+					if (b == '\r') {
+						cr = true;
+						count--;
+						continue;
+					}
+					if (b == '\n' || cr) {
+						count--;
+						break;
+					}
+				}
+
+				if (position >= inputLength && b == '\r' || b == '\n')
+					count++;
+
+				if (count >= 8192 || count + text.Length >= 8192)
+					throw new InvalidOperationException ("Line too long.");
+
+				if (count <= 0) {
+					position = i + 1;
+					break;
+				}
+
+				text.Append (encoding.GetString (InputBuffer, position, count));
+				position = i + 1;
+
+				if (i >= inputLength) {
+					b = InputBuffer [inputLength - 1];
+					if (b != '\r' && b != '\n')
+						continue;
+					FillBuffer();
+					if (b == '\r' && inputLength > 0 && InputBuffer[0] == '\n')
+						position++;
+				}
+				break;
+			} while (true);
+
+			if (text.Length == 0) {
+				return null;
+			}
+
+			return text.ToString ();
+		}
+
+		bool GetRequestLine ()
+		{
+			string req;
+			try {
+				while (true) {
+					req = ReadRequestLine ();
+					if (req == null) {
+						GotSomeInput = false;
+						return false;
+					}
+
+					req = req.Trim ();
+					// Ignore empty lines before the actual request.
+					if (req.Length > 0)
+						break;
+				}
+			} catch (Exception) {
+				GotSomeInput = false;
+				return false;
+			}
+
+			string [] s = req.Split (' ');
+
+			switch (s.Length) {
+			case 2:
+				verb = s [0].Trim ();
+				path = s [1].Trim ();
+				break;
+			case 3:
+				verb = s [0].Trim ();
+				path = s [1].Trim ();
+				protocol = s [2].Trim ();
+				break;
+			default:
+				return false;
+			}
+
+			int qmark = path.IndexOf ('?');
+			if (qmark != -1) {
+				queryString = path.Substring (qmark + 1);
+				path = path.Substring (0, qmark);
+			}
+			
+			path = GetSafePath (path);
+			if (path.StartsWith ("/~/")) {
+				// Not sure about this. It makes request such us /~/dir/file work
+				path = path.Substring (2);
+			}
+
+			return true;
+		}
+
+		static string GetSafePath (string path)
+		{
+			bool appendSlash = path.EndsWith ("/");
+
+			path = HttpUtility.UrlDecode (path);
+			path = path.Replace ('\\','/');
+			while (path.IndexOf ("//") != -1)
+				path = path.Replace ("//", "/");
+
+			string [] parts = path.Split ('/');
+			var result = new List<string> (parts.Length);
+			
+			int end = parts.Length;
+			for (int i = 0; i < end; i++) {
+				string current = parts [i];
+				if (current.Length == 0 || current == "." )
+					continue;
+
+				if (current == "..") {
+					if (result.Count > 0)
+						result.RemoveAt (result.Count - 1);
+					continue;
+				}
+
+				result.Add (current);
+			}
+
+			if (result.Count == 0)
+				return "/";
+
+			var res = new StringBuilder();
+			foreach (var part in result) {
+				res.Append ('/');
+				res.Append (part);
+			}
+
+			if (appendSlash)
+				res.Append ('/');
+			return res.ToString ();
+		}
+		
+		public void ReadRequestData ()
+		{
+			if (!GetRequestLine ())
+				throw new RequestLineException ();
+
+			if (protocol == null) {
+				protocol = "HTTP/1.0";
+			}
+		}
+	}
+}
+
diff --git a/src/Mono.WebServer/LingeringNetworkStream.cs b/src/Mono.WebServer/LingeringNetworkStream.cs
new file mode 100644
index 0000000..e4f4b38
--- /dev/null
+++ b/src/Mono.WebServer/LingeringNetworkStream.cs
@@ -0,0 +1,100 @@
+//
+// Mono.WebServer.LingeringNetworkStream
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//
+// (C) Copyright 2004 Novell, Inc. (http://www.novell.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.Sockets;
+
+namespace Mono.WebServer
+{
+	public class LingeringNetworkStream : NetworkStream 
+	{
+		const int USECONDS_TO_LINGER = 2000000;
+		const int MAX_USECONDS_TO_LINGER = 30000000;
+		// We dont actually use the data from this buffer. So we cache it...
+		static byte [] buffer;
+
+		public LingeringNetworkStream (Socket sock, bool owns) : base (sock, owns)
+		{
+			EnableLingering = true;
+			OwnsSocket = owns;
+		}
+
+		public bool OwnsSocket { get; private set; }
+
+		public bool EnableLingering { get; set; }
+
+		void LingeringClose ()
+		{
+			int waited = 0;
+
+			if (!Connected)
+				return;
+
+			try {
+				Socket.Shutdown (SocketShutdown.Send);
+				DateTime start = DateTime.UtcNow;
+				while (waited < MAX_USECONDS_TO_LINGER) {
+					int nread = 0;
+					try {
+						if (!Socket.Poll (USECONDS_TO_LINGER, SelectMode.SelectRead))
+							break;
+
+						if (buffer == null)
+							buffer = new byte [512];
+
+						nread = Socket.Receive (buffer, 0, buffer.Length, 0);
+					} catch { }
+
+					if (nread == 0)
+						break;
+
+					waited += (int) (DateTime.UtcNow - start).TotalMilliseconds * 1000;
+				}
+			} catch {
+				// ignore - we don't care, we're closing anyway
+			}
+		}
+
+		public override void Close ()
+		{
+			if (EnableLingering) {
+				try {
+					LingeringClose ();
+				} finally {
+					base.Close ();
+				}
+			}
+			else
+				base.Close ();
+		}
+
+		public bool Connected {
+			get { return Socket.Connected; }
+		}
+	}
+}
diff --git a/src/Mono.WebServer/LockRecursionException.cs b/src/Mono.WebServer/LockRecursionException.cs
new file mode 100644
index 0000000..fc14431
--- /dev/null
+++ b/src/Mono.WebServer/LockRecursionException.cs
@@ -0,0 +1,54 @@
+/*
+ * System.Threading.LockRecursionException
+ *
+ * Author(s)
+ * 	Marek Safar <marek.safar at gmail.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.Runtime.Serialization;
+
+namespace System.Threading
+{
+	[Serializable]
+	class LockRecursionException : Exception
+	{
+		public LockRecursionException ()
+		{
+		}
+
+		public LockRecursionException (string message) 
+			: base (message)
+		{
+		}
+
+		public LockRecursionException (string message, Exception e) 
+			: base (message, e)
+		{
+		}
+
+		protected LockRecursionException (SerializationInfo info, StreamingContext sc)
+			 : base (info, sc)
+		{
+		}
+	}
+}
diff --git a/src/Mono.WebServer/LockRecursionPolicy.cs b/src/Mono.WebServer/LockRecursionPolicy.cs
new file mode 100644
index 0000000..0437387
--- /dev/null
+++ b/src/Mono.WebServer/LockRecursionPolicy.cs
@@ -0,0 +1,36 @@
+/*
+ * System.Threading.LockRecursionPolicy
+ *
+ * Author(s)
+ * 	Marek Safar <marek.safar at gmail.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.
+ */
+
+
+namespace System.Threading
+{
+	[Serializable]
+	enum LockRecursionPolicy
+	{
+		NoRecursion,
+		SupportsRecursion
+	}
+}
diff --git a/src/Mono.WebServer/Log/FileLogger.cs b/src/Mono.WebServer/Log/FileLogger.cs
new file mode 100644
index 0000000..e43642e
--- /dev/null
+++ b/src/Mono.WebServer/Log/FileLogger.cs
@@ -0,0 +1,86 @@
+//
+// FileLogger.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.IO;
+
+namespace Mono.WebServer.Log {
+	class FileLogger : ILogger {
+		StreamWriter writer;
+
+		readonly object write_lock = new object ();
+
+		~FileLogger ()
+		{
+			Close ();
+		}
+
+		public void Open (string path)
+		{
+			if (path == null)
+				throw new ArgumentNullException ("path");
+
+			lock (write_lock) {
+				Close ();
+				Stream stream = File.Open (path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
+				stream.Seek (0, SeekOrigin.End);
+				writer = new StreamWriter (stream);
+			}
+		}
+
+		public void Write (LogLevel level, string text)
+		{
+			if (writer == null)
+				return;
+
+			lock (write_lock) {
+				if (writer == null)
+					return;
+
+				writer.WriteLine (text);
+				writer.Flush ();
+			}
+		}
+
+		public void Close ()
+		{
+			lock (write_lock) {
+				if (writer == null)
+					return;
+
+				try {
+					writer.Flush ();
+					writer.Close ();
+				} catch (ObjectDisposedException) {
+					// Already done
+				}
+				writer = null;
+			}
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Log/ILogger.cs b/src/Mono.WebServer/Log/ILogger.cs
new file mode 100644
index 0000000..cc26d29
--- /dev/null
+++ b/src/Mono.WebServer/Log/ILogger.cs
@@ -0,0 +1,35 @@
+//
+// ILogger.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.
+//
+
+namespace Mono.WebServer.Log
+{
+	public interface ILogger
+	{
+		void Write (LogLevel level, string text);
+	}
+}
diff --git a/src/Mono.WebServer/Log/LogLevel.cs b/src/Mono.WebServer/Log/LogLevel.cs
new file mode 100644
index 0000000..61a348d
--- /dev/null
+++ b/src/Mono.WebServer/Log/LogLevel.cs
@@ -0,0 +1,43 @@
+//
+// LogLevel.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Log {
+	[Flags]
+	public enum LogLevel
+	{
+		None     = 0x00,
+		Error    = 0x01,
+		Warning  = 0x02,
+		Notice   = 0x04,
+		Debug    = 0x08,
+		Standard = Error | Warning | Notice,
+		All     = Error | Warning | Notice | Debug
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Log/Logger.cs b/src/Mono.WebServer/Log/Logger.cs
new file mode 100644
index 0000000..6254de2
--- /dev/null
+++ b/src/Mono.WebServer/Log/Logger.cs
@@ -0,0 +1,151 @@
+//
+// Logger.cs: Logs server events.
+//
+// Author:
+//   Brian Nickel (brian.nickel at gmail.com)
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (C) 2007 Brian Nickel
+// Copyright (C) 2013 Leonardo Taglialegne
+// 
+// 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.Collections.Generic;
+using System.Globalization;
+using System.Threading;
+using System.Diagnostics;
+
+namespace Mono.WebServer.Log {
+	public static class Logger
+	{
+		static readonly List<ILogger> loggers = new List<ILogger> ();
+		static readonly FileLogger file_logger = new FileLogger ();
+
+		static readonly object write_lock = new object ();
+
+		#region Public Static Properties
+
+		public static LogLevel Level { get; set; }
+
+		public static bool WriteToConsole { get; set; }
+
+		public static bool Verbose { get; set; }
+
+		public static string Name { get; set; }
+
+		static int? ThreadId {
+			get {
+				if (Verbose && (Level & LogLevel.Debug) != LogLevel.None)
+					return Thread.CurrentThread.ManagedThreadId;
+				return null;
+			}
+		}
+
+
+		static int? ProcessId {
+			get {
+				if (Verbose && (Level & LogLevel.Debug) != LogLevel.None)
+					return Process.GetCurrentProcess ().Id;
+				return null;
+			}
+		}
+		#endregion
+		
+		static Logger ()
+		{
+			Level = LogLevel.Standard;
+			loggers.Add (file_logger);
+		}
+		
+		#region Public Static Methods
+
+		public static void AddLogger (ILogger logger)
+		{
+			loggers.Add (logger);
+		}
+		
+		public static void Open (string path)
+		{
+			file_logger.Open (path);
+		}
+
+		public static void Write (LogLevel level, string format, params object [] args)
+		{
+			Write (level, CultureInfo.CurrentCulture, format, args);
+		}
+
+		public static void Write (Exception e)
+		{
+			if (e == null)
+				throw new ArgumentNullException ("e");
+			Write (LogLevel.Error, e.Message);
+			if(e.StackTrace != null)
+				foreach(var line in e.StackTrace.Split(new []{Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries))
+					Write (LogLevel.Error, line);
+		}
+
+		static string GetFormatString ()
+		{
+			return ThreadId == null 
+				? "[{2}] {3,-7}: {4}" 
+				: Name == null
+					? "{1,2} [{2}] {3,-7}: {4}"
+					: "{0,5}:{1,2} {5,-8} [{2}] {3,-7}: {4}";
+		}
+
+		public static void Write (LogLevel level, string message)
+		{
+			if ((Level & level) == LogLevel.None)
+				return;
+
+			var format = GetFormatString ();
+			string time = Verbose
+				? DateTime.Now.ToString ("yyyy-MM-dd HH:mm:ss.ffffff")
+				: DateTime.Now.ToString ("yyyy-MM-dd HH:mm:ss");
+			string text = String.Format (CultureInfo.CurrentCulture, format, ProcessId, ThreadId, time, level, message, Name);
+
+			if (WriteToConsole)
+				lock (write_lock)
+					if (Verbose)
+						Console.WriteLine (text);
+					else
+						Console.WriteLine (message);
+
+			foreach(var logger in loggers)
+				logger.Write (level, text);
+		}
+
+		static void Write (LogLevel level,
+		                   IFormatProvider provider,
+		                   string format, params object [] args)
+		{
+			Write (level, String.Format (provider, format, args));
+		}
+
+		public static void Close ()
+		{
+			file_logger.Close ();
+		}
+		
+		#endregion
+	}
+}
diff --git a/src/Mono.WebServer/Makefile.am b/src/Mono.WebServer/Makefile.am
index 1a19cb2..911642e 100644
--- a/src/Mono.WebServer/Makefile.am
+++ b/src/Mono.WebServer/Makefile.am
@@ -11,7 +11,7 @@ GACUTIL4=$(GACUTIL) -package 4.5
 noinst_SCRIPTS= $(monowebserver4_install)
 
 CLEANFILES = 4.0/Mono.WebServer2.dll*
-EXTRA_DIST = AssemblyInfo4.cs.in
+EXTRA_DIST = $(sources) AssemblyInfo4.cs.in Mono.WebServer.sources
 
 sources = $(shell cat $(srcdir)/Mono.WebServer.sources)
 
diff --git a/src/Mono.WebServer/Makefile.in b/src/Mono.WebServer/Makefile.in
index 851de46..bd4cd70 100644
--- a/src/Mono.WebServer/Makefile.in
+++ b/src/Mono.WebServer/Makefile.in
@@ -287,7 +287,7 @@ monowebserver4_references = -r:System.Web.dll -r:System.Configuration.dll -r:Mon
 GACUTIL4 = $(GACUTIL) -package 4.5
 noinst_SCRIPTS = $(monowebserver4_install)
 CLEANFILES = 4.0/Mono.WebServer2.dll*
-EXTRA_DIST = AssemblyInfo4.cs.in
+EXTRA_DIST = $(sources) AssemblyInfo4.cs.in Mono.WebServer.sources
 sources = $(shell cat $(srcdir)/Mono.WebServer.sources)
 monowebserver4_build_sources = $(addprefix $(srcdir)/, $(sources)) $(addprefix $(top_builddir)/src/Mono.WebServer/, AssemblyInfo4.cs)
 all: all-am
diff --git a/src/Mono.WebServer/MapPathEventArgs.cs b/src/Mono.WebServer/MapPathEventArgs.cs
new file mode 100644
index 0000000..660cbcb
--- /dev/null
+++ b/src/Mono.WebServer/MapPathEventArgs.cs
@@ -0,0 +1,67 @@
+//
+// Mono.WebServer.MapPathEventArgs
+//
+// Authors:
+//	Daniel Lopez Ridruejo
+// 	Gonzalo Paniagua Javier
+//
+// Documentation:
+//	Brian Nickel
+//
+// Copyright (c) 2002 Daniel Lopez Ridruejo.
+//           (c) 2002,2003 Ximian, Inc.
+//           All rights reserved.
+// (C) Copyright 2004-2010 Novell, Inc. (http://www.novell.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;
+
+namespace Mono.WebServer
+{
+	public class MapPathEventArgs : EventArgs
+	{
+		// Contains the virtual path, as used in the request.
+
+		// Contains the physical "mapped" path.
+		string mapped;
+		
+		// Indicates whether or not the path has been mapped.
+
+		public MapPathEventArgs (string path)
+		{
+			Path = path;
+			IsMapped = false;
+		}
+
+		public string Path { get; private set; }
+
+		public bool IsMapped { get; private set; }
+
+		public string MappedPath {
+			get { return mapped; }
+			set {
+				mapped = value;
+				IsMapped = !String.IsNullOrEmpty (value);
+			}
+		}
+	}
+}
diff --git a/src/Mono.WebServer/MapPathEventHandler.cs b/src/Mono.WebServer/MapPathEventHandler.cs
new file mode 100644
index 0000000..5688225
--- /dev/null
+++ b/src/Mono.WebServer/MapPathEventHandler.cs
@@ -0,0 +1,39 @@
+//
+// Mono.WebServer.MapPathEventHandler
+//
+// Authors:
+//	Daniel Lopez Ridruejo
+// 	Gonzalo Paniagua Javier
+//
+// Documentation:
+//	Brian Nickel
+//
+// Copyright (c) 2002 Daniel Lopez Ridruejo.
+//           (c) 2002,2003 Ximian, Inc.
+//           All rights reserved.
+// (C) Copyright 2004-2010 Novell, Inc. (http://www.novell.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.
+//
+
+namespace Mono.WebServer
+{
+	public delegate void MapPathEventHandler (object sender, MapPathEventArgs args);
+}
diff --git a/src/Mono.WebServer/Mono.WebServer.sources b/src/Mono.WebServer/Mono.WebServer.sources
new file mode 100644
index 0000000..98dde7a
--- /dev/null
+++ b/src/Mono.WebServer/Mono.WebServer.sources
@@ -0,0 +1,53 @@
+./ApplicationServer.cs
+./BaseApplicationHost.cs
+./BaseRequestBroker.cs
+./EndOfRequestHandler.cs
+./FinePlatformID.cs
+./HttpErrors.cs
+./IApplicationHost.cs
+./IdentityToken.cs
+./InitialWorkerRequest.cs
+./IRequestBroker.cs
+./LingeringNetworkStream.cs
+./LockRecursionException.cs
+./LockRecursionPolicy.cs
+./Log/FileLogger.cs
+./Log/ILogger.cs
+./Log/Logger.cs
+./Log/LogLevel.cs
+./MapPathEventArgs.cs
+./MapPathEventHandler.cs
+./MonoWorkerRequest.cs
+./Options/ConfigurationManager.cs
+./Options/ConfigurationManagerExtensions.cs
+./Options/ConfigurationManager.Fields.cs
+./Options/Descriptions.cs
+./Options/IHelpConfigurationManager.cs
+./Options/Options.cs
+./Options/ServerConfigurationManager.cs
+./Options/Settings/BoolSetting.cs
+./Options/Settings/EnumSetting.cs
+./Options/Settings/Int32Setting.cs
+./Options/Settings/ISetting.cs
+./Options/Settings/NullableInt32Setting.cs
+./Options/Settings/NullableSetting.cs
+./Options/Settings/NullableUInt16Setting.cs
+./Options/Settings/Parser.cs
+./Options/Settings/Setting.cs
+./Options/Settings/SettingsCollection.cs
+./Options/Settings/SettingSource.cs
+./Options/Settings/StringSetting.cs
+./Options/Settings/UInt16Setting.cs
+./Options/Settings/UInt32Setting.cs
+./Paths.cs
+./Platform.cs
+./RequestData.cs
+./RequestLineException.cs
+./SearchPattern.cs
+./UnregisterRequestEventArgs.cs
+./UnregisterRequestEventHandler.cs
+./Version.cs
+./VPathToHost.cs
+./WebSource.cs
+./WebTrace.cs
+./Worker.cs
diff --git a/src/Mono.WebServer/MonoWorkerRequest.cs b/src/Mono.WebServer/MonoWorkerRequest.cs
new file mode 100644
index 0000000..de2c738
--- /dev/null
+++ b/src/Mono.WebServer/MonoWorkerRequest.cs
@@ -0,0 +1,626 @@
+//
+// Mono.WebServer.MonoWorkerRequest
+//
+// Authors:
+//	Daniel Lopez Ridruejo
+// 	Gonzalo Paniagua Javier
+//
+// Documentation:
+//	Brian Nickel
+//
+// Copyright (c) 2002 Daniel Lopez Ridruejo.
+//           (c) 2002,2003 Ximian, Inc.
+//           All rights reserved.
+// (C) Copyright 2004-2010 Novell, Inc. (http://www.novell.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.Collections.Specialized;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Web;
+using System.Web.Hosting;
+using Mono.WebServer.Log;
+
+namespace Mono.WebServer
+{	
+	public abstract class MonoWorkerRequest : SimpleWorkerRequest
+	{
+		const string DEFAULT_EXCEPTION_HTML = "<html><head><title>Runtime Error</title></head><body>An exception ocurred:<pre>{0}</pre></body></html>";
+		static readonly char[] mapPathTrimStartChars = { '/' };
+
+		static bool checkFileAccess = true;
+		readonly static bool needToReplacePathSeparator;
+		readonly static char pathSeparatorChar;
+		
+		readonly IApplicationHost appHostBase;
+		Encoding encoding;
+		Encoding headerEncoding;
+		byte [] queryStringBytes;
+		string hostVPath;
+		string hostPath;
+		string hostPhysicalRoot;
+		EndOfSendNotification end_send;
+		object end_send_data;
+		X509Certificate client_cert;
+		NameValueCollection server_variables;
+		bool inUnhandledException;
+		
+ 		// as we must have the client certificate (if provided) then we're able to avoid
+ 		// pre-calculating some items (and cache them if we have to calculate)
+ 		string cert_cookie;
+ 		string cert_issuer;
+ 		string cert_serial;
+ 		string cert_subject;
+
+		protected byte[] server_raw;
+		protected byte[] client_raw;
+
+		public event MapPathEventHandler MapPathEvent;
+		public event EndOfRequestHandler EndOfRequestEvent;
+
+		public abstract int RequestId { get; }
+
+		protected static bool RunningOnWindows { get; private set; }
+
+		public static bool CheckFileAccess {
+			get { return checkFileAccess; }
+			set { checkFileAccess = value; }
+		}
+		
+		// Gets the physical path of the application host of the
+		// current instance.
+		string HostPath {
+			get {
+				if (hostPath == null)
+					hostPath = appHostBase.Path;
+
+				return hostPath;
+			}
+		}
+
+		// Gets the virtual path of the application host of the
+		// current instance.
+		string HostVPath {
+			get {
+				if (hostVPath == null)
+					hostVPath = appHostBase.VPath;
+
+				return hostVPath;
+			}
+		}
+
+		string HostPhysicalRoot {
+			get {
+				if (hostPhysicalRoot == null)
+					hostPhysicalRoot = appHostBase.Server.PhysicalRoot;
+
+				return hostPhysicalRoot;
+			}
+		}
+		
+		protected virtual Encoding Encoding {
+			get {
+				if (encoding == null)
+					encoding = Encoding.GetEncoding (28591);
+
+				return encoding;
+			}
+			set {
+				encoding = value;
+			}
+		}
+
+		protected virtual Encoding HeaderEncoding {
+			get {
+				if (headerEncoding == null) {
+					HttpContext ctx = HttpContext.Current;
+					HttpResponse response = ctx != null ? ctx.Response : null;
+					Encoding enc = inUnhandledException ? null :
+						response != null ? response.HeaderEncoding : null;
+					headerEncoding = enc ?? Encoding;
+				}
+				return headerEncoding;
+			}
+		}
+		
+		static MonoWorkerRequest ()
+		{
+			PlatformID pid = Environment.OSVersion.Platform;
+			RunningOnWindows = ((int) pid != 128 && pid != PlatformID.Unix && pid != PlatformID.MacOSX);
+
+			if (Path.DirectorySeparatorChar != '/') {
+				needToReplacePathSeparator = true;
+				pathSeparatorChar = Path.DirectorySeparatorChar;
+			}
+			
+			try {
+				string v = ConfigurationManager.AppSettings ["MonoServerCheckHiddenFiles"];
+				if (!String.IsNullOrEmpty (v)) {
+					if (!Boolean.TryParse (v, out checkFileAccess))
+						checkFileAccess = true;
+				}
+			} catch (Exception) {
+				// ignore
+				checkFileAccess = true;
+			}
+		}
+
+		protected MonoWorkerRequest (IApplicationHost appHost)
+			: base (String.Empty, String.Empty, null)
+		{
+			if (appHost == null)
+				throw new ArgumentNullException ("appHost");
+
+			appHostBase = appHost;
+		}
+
+		public override string GetAppPath ()
+		{
+			return HostVPath;
+		}
+
+		public override string GetAppPathTranslated ()
+		{
+			return HostPath;
+		}
+
+		public override string GetFilePathTranslated ()
+		{
+			return MapPath (GetFilePath ());
+		}
+
+		public override string GetLocalAddress ()
+		{
+			return "localhost";
+		}
+
+		public override string GetServerName ()
+		{
+			string hostHeader = GetKnownRequestHeader(HeaderHost);
+			if (String.IsNullOrEmpty (hostHeader)) {
+				hostHeader = GetLocalAddress ();
+			} else {
+				int colonIndex = hostHeader.IndexOf (':');
+				if (colonIndex > 0) {
+					hostHeader = hostHeader.Substring (0, colonIndex);
+				} else if (colonIndex == 0) {
+					hostHeader = GetLocalAddress ();
+				}
+			}
+			return hostHeader;
+		}
+
+		public override int GetLocalPort ()
+		{
+			return 0;
+		}
+
+		public override byte [] GetPreloadedEntityBody ()
+		{
+			return null;
+		}
+
+		public override byte [] GetQueryStringRawBytes ()
+		{
+			if (queryStringBytes == null) {
+				string queryString = GetQueryString ();
+				if (queryString != null)
+					queryStringBytes = Encoding.GetBytes (queryString);
+			}
+
+			return queryStringBytes;
+		}
+
+		// Invokes the registered delegates one by one until the path is mapped.
+		//
+		// Parameters:
+		//    path = virutal path of the request.
+		//
+		// Returns a string containing the mapped physical path of the request, or null if
+		// the path was not successfully mapped.
+		//
+		string DoMapPathEvent (string path)
+		{
+			if (MapPathEvent != null) {
+				var args = new MapPathEventArgs (path);
+				foreach (MapPathEventHandler evt in MapPathEvent.GetInvocationList ()) {
+					evt (this, args);
+					if (args.IsMapped)
+						return args.MappedPath;
+				}
+			}
+
+			return null;
+		}
+
+		// The logic here is as follows:
+		//
+		// If path is equal to the host's virtual path (including trailing slash),
+		// return the host virtual path.
+		//
+		// If path is absolute (starts with '/') then check if it's under our host vpath. If
+		// it is, base the mapping under the virtual application's physical path. If it
+		// isn't use the physical root of the application server to return the mapped
+		// path. If you have just one application configured, then the values computed in
+		// both of the above cases will be the same. If you have several applications
+		// configured for this xsp/mod-mono-server instance, then virtual paths outside our
+		// application virtual path will return physical paths relative to the server's
+		// physical root, not application's. This is consistent with the way IIS worker
+		// request works. See bug #575600
+		//
+		public override string MapPath (string path)
+		{
+			string eventResult = DoMapPathEvent (path);
+			if (eventResult != null)
+				return eventResult;
+
+			string hostVPath = HostVPath;
+			int hostVPathLen = HostVPath.Length;
+			int pathLen = path != null ? path.Length : 0;
+#if NET_2_0
+			bool inThisApp = path.StartsWith (hostVPath, StringComparison.Ordinal);
+#else
+			bool inThisApp = path.StartsWith (hostVPath);
+#endif
+			if (pathLen == 0 || (inThisApp && (pathLen == hostVPathLen || (pathLen == hostVPathLen + 1 && path [pathLen - 1] == '/')))) {
+				if (needToReplacePathSeparator)
+					return HostPath.Replace ('/', pathSeparatorChar);
+				return HostPath;
+			}
+
+			string basePath = null;
+			switch (path [0]) {
+				case '~':
+					if (path.Length >= 2 && path [1] == '/')
+						path = path.Substring (1);
+					break;
+
+				case '/':
+					if (!inThisApp)
+						basePath = HostPhysicalRoot;
+					break;
+			}
+
+			if (basePath == null)
+				basePath = HostPath;
+			
+			if (inThisApp && (path.Length == hostVPathLen || path [hostVPathLen] == '/'))
+				path = path.Substring (hostVPathLen + 1);
+			
+			path = path.TrimStart (mapPathTrimStartChars);
+			if (needToReplacePathSeparator)
+				path = path.Replace ('/', pathSeparatorChar);
+			
+			return Path.Combine (basePath, path);
+		}
+
+		protected abstract bool GetRequestData ();		
+
+		public bool ReadRequestData ()
+		{
+			return GetRequestData ();
+		}
+
+		static void LocationAccessible (string localPath)
+		{
+			bool doThrow = false;
+			
+			if (RunningOnWindows) {
+				try {
+					var fi = new FileInfo (localPath);
+					FileAttributes attr = fi.Attributes;
+
+					if ((attr & FileAttributes.Hidden) != 0 || (attr & FileAttributes.System) != 0)
+						doThrow = true;
+				} catch (Exception) {
+					// ignore, will be handled in system.web
+					return;
+				}
+			} else {
+				// throw only if the file exists, let system.web handle the request
+				// otherwise 
+				if (File.Exists (localPath) || Directory.Exists (localPath))
+					if (Path.GetFileName (localPath) [0] == '.')
+						doThrow = true;
+			}
+
+			if (doThrow)
+				throw new HttpException (403, "Forbidden.");
+		}
+		
+		void AssertFileAccessible ()
+		{
+			if (!checkFileAccess)
+				return;
+			
+			string localPath = GetFilePathTranslated ();
+			if (String.IsNullOrEmpty (localPath))
+				return;
+
+			char dirsep = Path.DirectorySeparatorChar;
+			string appPath = GetAppPathTranslated ();
+			string[] segments = localPath.Substring (appPath.Length).Split (dirsep);
+
+			var sb = new StringBuilder (appPath);
+			foreach (string s in segments) {
+				if (s.Length == 0)
+					continue;
+				
+				if (s [0] != '.') {
+					sb.Append (s);
+					sb.Append (dirsep);
+					continue;
+				}
+
+				sb.Append (s);
+				LocationAccessible (sb.ToString ());
+			}
+		}
+
+		public void ProcessRequest ()
+		{
+			string error = null;
+			inUnhandledException = false;
+			
+			try {
+				AssertFileAccessible ();
+				HttpRuntime.ProcessRequest (this);
+			} catch (HttpException ex) {
+				inUnhandledException = true;
+				error = ex.GetHtmlErrorMessage ();
+			} catch (Exception ex) {
+				inUnhandledException = true;
+				var hex = new HttpException (400, "Bad request", ex);
+				error = hex.GetHtmlErrorMessage ();
+			}
+
+			if (!inUnhandledException)
+				return;
+			
+			if (error.Length == 0)
+				error = String.Format (DEFAULT_EXCEPTION_HTML, "Unknown error");
+
+			try {
+				SendStatus (400, "Bad request");
+				SendUnknownResponseHeader ("Connection", "close");
+				SendUnknownResponseHeader ("Date", DateTime.Now.ToUniversalTime ().ToString ("r"));
+				
+				Encoding enc = Encoding.UTF8;
+				
+				byte[] bytes = enc.GetBytes (error);
+				
+				SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
+				SendUnknownResponseHeader ("Content-Length", bytes.Length.ToString ());
+				SendResponseFromMemory (bytes, bytes.Length);
+				FlushResponse (true);
+			} catch (Exception ex) { // should "never" happen
+				Logger.Write (LogLevel.Error, "Error while processing a request: ");
+				Logger.Write (ex);
+				throw;
+			}
+		}
+
+		public override void EndOfRequest ()
+		{
+			if (EndOfRequestEvent != null)
+				EndOfRequestEvent (this);
+
+			if (end_send != null)
+				end_send (this, end_send_data);
+		}		
+
+		public override void SetEndOfSendNotification (EndOfSendNotification callback, object extraData)
+		{
+			end_send = callback;
+			end_send_data = extraData;
+		}
+
+		public override void SendCalculatedContentLength (int contentLength)
+		{
+			//FIXME: Should we ignore this for apache2?
+			SendUnknownResponseHeader ("Content-Length", contentLength.ToString ());
+		}
+
+		public override void SendKnownResponseHeader (int index, string value)
+		{
+			if (HeadersSent ())
+				return;
+
+			string headerName = GetKnownResponseHeaderName (index);
+			SendUnknownResponseHeader (headerName, value);
+		}
+
+		protected void SendFromStream (Stream stream, long offset, long length)
+		{
+			if (offset < 0 || length <= 0)
+				return;
+			
+			long stLength = stream.Length;
+			if (offset + length > stLength)
+				length = stLength - offset;
+
+			if (offset > 0)
+				stream.Seek (offset, SeekOrigin.Begin);
+
+			var fileContent = new byte [8192];
+			int count = fileContent.Length;
+			while (length > 0 && (count = stream.Read (fileContent, 0, count)) != 0) {
+				SendResponseFromMemory (fileContent, count);
+				length -= count;
+				// Keep the System. prefix
+				count = (int) System.Math.Min (length, fileContent.Length);
+			}
+		}
+
+		public override void SendResponseFromFile (string filename, long offset, long length)
+		{
+			FileStream file = null;
+			try {
+				file = File.OpenRead (filename);
+				SendFromStream (file, offset, length);
+			} finally {
+				if (file != null)
+					file.Close ();
+			}
+		}
+
+		public override void SendResponseFromFile (IntPtr handle, long offset, long length)
+		{
+			Stream file = null;
+			try {
+				file = new FileStream (handle, FileAccess.Read);
+				SendFromStream (file, offset, length);
+			} finally {
+				if (file != null)
+					file.Close ();
+			}
+		}
+		
+		public override string GetServerVariable (string name)
+		{
+			if (server_variables == null)
+				return String.Empty;
+
+			if (IsSecure ()) {
+	 			X509Certificate client = ClientCertificate;
+	 			switch (name) {
+ 				case "CERT_COOKIE":
+ 					if (cert_cookie == null) {
+ 						if (client == null)
+ 							cert_cookie = String.Empty;
+ 						else
+ 							cert_cookie = client.GetCertHashString ();
+ 					}
+ 					return cert_cookie;
+	 			case "CERT_ISSUER":
+	 				if (cert_issuer == null) {
+	 					if (client == null)
+	 						cert_issuer = String.Empty;
+	 					else
+							cert_issuer = client.Issuer;
+	 				}
+	 				return cert_issuer;
+	 			case "CERT_SERIALNUMBER":
+	 				if (cert_serial == null) {
+	 					if (client == null)
+	 						cert_serial = String.Empty;
+	 					else
+	 						cert_serial = client.GetSerialNumberString ();
+	 				}
+	 				return cert_serial;
+	 			case "CERT_SUBJECT":
+	 				if (cert_subject == null) {
+	 					if (client == null)
+	 						cert_subject = String.Empty;
+	 					else
+							cert_subject = client.Subject;
+	 				}
+					return cert_subject;
+	 			}
+			}
+
+			string s = server_variables [name];
+			return s ?? String.Empty;
+		}
+
+		public void AddServerVariable (string name, string value)
+		{
+			if (server_variables == null)
+				server_variables = new NameValueCollection ();
+
+			server_variables.Add (name, value);
+		}
+
+		#region Client Certificate Support
+
+		public X509Certificate ClientCertificate {
+			get {
+				if ((client_cert == null) && (client_raw != null))
+					client_cert = new X509Certificate (client_raw);
+				return client_cert;
+			}
+		}
+
+		public void SetClientCertificate (byte[] rawcert)
+		{
+			client_raw = rawcert;
+		}
+
+		public override byte[] GetClientCertificate ()
+		{
+			return client_raw;
+		}		
+
+		public override byte[] GetClientCertificateBinaryIssuer ()
+		{
+			if (ClientCertificate == null)
+				return base.GetClientCertificateBinaryIssuer ();
+			// TODO: not 100% sure of the content
+			return new byte [0];
+		}
+		
+		public override int GetClientCertificateEncoding ()
+		{
+			if (ClientCertificate == null)
+				return base.GetClientCertificateEncoding ();
+			return 0;
+		}
+		
+		public override byte[] GetClientCertificatePublicKey ()
+		{
+			if (ClientCertificate == null)
+				return base.GetClientCertificatePublicKey ();
+			return ClientCertificate.GetPublicKey ();
+		}
+
+		public override DateTime GetClientCertificateValidFrom ()
+		{
+			if (ClientCertificate == null)
+				return base.GetClientCertificateValidFrom ();
+			return DateTime.Parse (ClientCertificate.GetEffectiveDateString ());
+		}
+
+		public override DateTime GetClientCertificateValidUntil ()
+		{
+			if (ClientCertificate == null)
+				return base.GetClientCertificateValidUntil ();
+			return DateTime.Parse (ClientCertificate.GetExpirationDateString ());
+		}
+		
+		#endregion
+
+		protected static string[] SplitAndTrim (string list)
+		{
+			if (String.IsNullOrEmpty (list))
+				return new string[0];
+			return (from f in list.Split (',')
+			        let trimmed =  f.Trim ()
+			        where trimmed.Length != 0
+			        select trimmed).ToArray ();
+		}
+	}
+}
+
diff --git a/src/Mono.WebServer/Options/ConfigurationManager.Fields.cs b/src/Mono.WebServer/Options/ConfigurationManager.Fields.cs
new file mode 100644
index 0000000..0ea5e5f
--- /dev/null
+++ b/src/Mono.WebServer/Options/ConfigurationManager.Fields.cs
@@ -0,0 +1,137 @@
+//
+// ConfigurationManager.Fields.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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 Mono.WebServer.Log;
+using Mono.WebServer.Options.Settings;
+
+namespace Mono.WebServer.Options {
+	public abstract partial class ConfigurationManager {
+		protected ConfigurationManager (string name)
+		{
+			settings = new SettingsCollection {help, version, verbose, printlog,
+			logFile, configFile, this.name,
+			loglevels};
+			this.name.MaybeUpdate (SettingSource.Default, name);
+		}
+
+		#region Baking fields
+		readonly BoolSetting help = new BoolSetting ("help", "Shows this help message and exits.", prototype: "?|h|help");
+		readonly BoolSetting version = new BoolSetting ("version", "Displays version information and exits.", "V|version");
+		readonly BoolSetting verbose = new BoolSetting ("verbose", "Prints extra messages. Mainly useful for debugging.", prototype: "v|verbose");
+		readonly BoolSetting printlog = new BoolSetting ("printlog", "Prints log messages to the console.", environment: "MONO_PRINTLOG|MONO_FCGI_PRINTLOG", defaultValue: true);
+
+		readonly StringSetting logFile = new StringSetting ("logfile", "Specifies a file to log events to.", "FastCgiLogFile", "MONO_LOGFILE|MONO_FCGI_LOGFILE");
+		readonly StringSetting configFile = new StringSetting ("configfile|config-file", Descriptions.ConfigFile);
+		readonly StringSetting name = new StringSetting ("name", "Specifies a name to print in the log");
+
+		readonly EnumSetting<LogLevel> loglevels = new EnumSetting<LogLevel> ("loglevels", Descriptions.LogLevels, "FastCgiLogLevels", "MONO_FCGI_LOGLEVELS", LogLevel.Standard);
+		#endregion
+
+		#region Typesafe properties
+		public bool Help {
+			get { return help; }
+		}
+		public bool Version {
+			get { return version; }
+		}
+		public bool Verbose {
+			get { return verbose; }
+		}
+		public bool PrintLog {
+			get { return printlog; }
+		}
+
+		public string LogFile {
+			get { return logFile; }
+		}
+		public string ConfigFile {
+			get { return configFile; }
+		}
+		public string Name {
+			get { return name; }
+		}
+
+		public LogLevel LogLevels {
+			get { return loglevels; }
+		}
+		#endregion
+
+		protected void Add (params ISetting[] settings)
+		{
+			if (settings == null) 
+				throw new ArgumentNullException ("settings");
+			foreach (ISetting setting in settings)
+				this.settings.Add (setting);
+		}
+
+		public void SetupLogger ()
+		{
+			Logger.Level = LogLevels;
+			OpenLogFile ();
+			Logger.WriteToConsole = PrintLog;
+			Logger.Verbose = Verbose;
+			Logger.Name = Name;
+		}
+
+		void OpenLogFile ()
+		{
+			try {
+				if (LogFile != null)
+					Logger.Open (LogFile);
+			} catch (Exception e) {
+				Logger.Write (LogLevel.Error, "Error opening log file: {0}", e.Message);
+				Logger.Write (LogLevel.Warning, "Events will not be logged to file.");
+			}
+		}
+
+		/// <summary>
+		/// If a configfile option was specified, tries to load
+		/// the configuration file
+		/// </summary>
+		/// <returns>false on failure, true on success or
+		/// option not present</returns>
+		public bool LoadConfigFile ()
+		{
+			try {
+				if (ConfigFile != null)
+					if(!TryLoadXmlConfig (ConfigFile))
+						return false;
+			} catch (ApplicationException e) {
+				Logger.Write (LogLevel.Error, e.Message);
+				return false;
+			} catch (System.Xml.XmlException e) {
+				Logger.Write (LogLevel.Error,
+					"Error reading XML configuration: {0}",
+					e.Message);
+				return false;
+			}
+			return true;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/ConfigurationManager.cs b/src/Mono.WebServer/Options/ConfigurationManager.cs
new file mode 100644
index 0000000..4af1bdf
--- /dev/null
+++ b/src/Mono.WebServer/Options/ConfigurationManager.cs
@@ -0,0 +1,144 @@
+//
+// ConfigurationManager.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.Globalization;
+using System.IO;
+using System.Xml;
+using Mono.Unix;
+using Mono.WebServer.Log;
+using NDesk.Options;
+using Mono.WebServer.Options.Settings;
+
+namespace Mono.WebServer.Options {
+	public abstract partial class ConfigurationManager {
+		const string EXCEPT_BAD_ELEM = "XML setting \"{0}={1}\" is invalid.";
+
+		readonly SettingsCollection settings;
+
+		[Obsolete]
+		internal SettingsCollection Settings {
+			get { return settings; }
+		}
+
+
+		public bool TryLoadXmlConfig (string file)
+		{
+			if (String.IsNullOrEmpty (file))
+				throw new ArgumentNullException ("file");
+			var doc = new XmlDocument ();
+			try {
+				doc.Load (file);
+			} catch (FileNotFoundException e) {
+				Console.Error.WriteLine("ERROR: Couldn't find configuration file {0}!", e.FileName);
+				return false;
+			}
+			if (Platform.IsUnix) {
+				var fileInfo = new UnixFileInfo (file);
+				ImportSettings (doc, true, file, fileInfo.OwnerUser.UserName, fileInfo.OwnerGroup.GroupName);
+			} else
+				ImportSettings (doc, true, file);
+			return true;
+		}
+		
+		[Obsolete]
+		public void ImportSettings (XmlDocument doc, bool insertEmptyValue)
+		{
+			ImportSettings (doc, insertEmptyValue, null);
+		}
+
+		void ImportSettings (XmlDocument doc, bool insertEmptyValue, string filename , string user = null, string group = null)
+		{
+			if (doc == null)
+				throw new ArgumentNullException ("doc");
+
+			var tags = doc.GetElementsByTagName ("Setting");
+			foreach (XmlElement setting in tags) {
+				string name = GetXmlValue (setting, "Name");
+				string value = Parse (GetXmlValue (setting, "Value"), filename, user, group);
+				if (name.Length == 0)
+					throw AppExcept (EXCEPT_BAD_ELEM, name, value);
+
+				if (settings.Contains (name)) {
+					if (insertEmptyValue || value.Length > 0)
+						settings [name].MaybeParseUpdate (SettingSource.Xml, value);
+				} else
+					Logger.Write (LogLevel.Warning, "Unrecognized xml setting: {0} with value {1}", name, value);
+			}
+		}
+
+		static string Parse (string value, string filename, string user, string group)
+		{
+			if (!String.IsNullOrEmpty (filename))
+				value = value.Replace ("$(filename)", Path.GetFileNameWithoutExtension (filename));
+			if (!String.IsNullOrEmpty (user))
+				value = value.Replace ("$(user)", user);
+			if (!String.IsNullOrEmpty (group))
+				value = value.Replace ("$(group)", group);
+			return value;
+		}
+
+		public OptionSet CreateOptionSet ()
+		{
+			var p = new OptionSet ();
+			foreach (ISetting setting in settings) {
+				var boolSetting = setting as Setting<bool>;
+				if (boolSetting != null) {
+					p.Add (setting.Prototype, setting.Description,
+					       v => boolSetting.MaybeUpdate (SettingSource.CommandLine, v != null));
+				} else {
+					ISetting setting1 = setting; // Used in closure, must copy
+					p.Add (setting.Prototype + "=", setting.Description,
+						v => { if (v != null) setting1.MaybeParseUpdate (SettingSource.CommandLine, v); } );
+				}
+			}
+			return p;
+		}
+
+		static ApplicationException AppExcept (string message, params object [] args)
+		{
+			return new ApplicationException (String.Format (
+				CultureInfo.InvariantCulture, message, args));
+		}
+
+		static string GetXmlValue (XmlElement elem, string name)
+		{
+			string value = elem.GetAttribute (name);
+			if (!String.IsNullOrEmpty (value))
+				return value;
+
+			foreach (XmlElement child in elem.GetElementsByTagName (name)) {
+				value = child.InnerText;
+				if (!String.IsNullOrEmpty (value))
+					return value;
+			}
+
+			return String.Empty;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/ConfigurationManagerExtensions.cs b/src/Mono.WebServer/Options/ConfigurationManagerExtensions.cs
new file mode 100644
index 0000000..00044c9
--- /dev/null
+++ b/src/Mono.WebServer/Options/ConfigurationManagerExtensions.cs
@@ -0,0 +1,73 @@
+//
+// ConfigurationManagerExtensions.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.Collections.Generic;
+using NDesk.Options;
+
+namespace Mono.WebServer.Options {
+	public static class ConfigurationManagerExtensions {
+
+		public static void PrintHelp<T> (this T configurationManager) where T : IHelpConfigurationManager
+		{
+			Version.Show ();
+			Console.WriteLine (configurationManager.Description);
+			Console.WriteLine ("Usage is:\n");
+			Console.WriteLine ("    {0} [...]", configurationManager.ProgramName);
+			Console.WriteLine ();
+			configurationManager.CreateOptionSet ().WriteOptionDescriptions (Console.Out);
+		}
+
+		public static bool LoadCommandLineArgs<T> (this T configurationManager, string [] cmd_args) where T : IHelpConfigurationManager
+		{
+			if (cmd_args == null)
+				throw new ArgumentNullException ("cmd_args");
+
+			OptionSet optionSet = configurationManager.CreateOptionSet ();
+
+			List<string> extra;
+			try {
+				extra = optionSet.Parse (cmd_args);
+			} catch (OptionException e) {
+				Console.WriteLine ("{0}: {1}", configurationManager.ProgramName, e.Message);
+				Console.WriteLine ("Try `{0} --help' for more information.", configurationManager.ProgramName);
+				return false;
+			}
+
+			if (extra.Count > 0) {
+				Console.Write ("Warning: unparsed command line arguments: ");
+				foreach (string s in extra) {
+					Console.Write ("{0} ", s);
+				}
+				Console.WriteLine ();
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/Descriptions.cs b/src/Mono.WebServer/Options/Descriptions.cs
new file mode 100644
index 0000000..64638c1
--- /dev/null
+++ b/src/Mono.WebServer/Options/Descriptions.cs
@@ -0,0 +1,93 @@
+//
+// Descriptions.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.
+//
+
+namespace Mono.WebServer.Options {
+	public static class Descriptions
+	{
+		public const string MaxConns = "Specifies the maximum number of concurrent connections the server should accept.";
+
+		public const string LogLevels = "Specifies what log levels to log. It can be any of the following values, or multiple if comma separated:\n" +
+			"* Debug\n" +
+			"* Notice\n" +
+			"* Warning\n" +
+			"* Error\n" +
+			"* Standard (Notice,Warning,Error)\n" +
+			"* All (Debug,Standard)\n" +
+			"This value is only used when \"logfile\" or \"printlog\" are set.";
+
+		public const string Socket = "Specifies the type of socket to listen on. Valid values are \"pipe\", \"unix\", and \"tcp\".\n" +
+			"\"pipe\" indicates to use piped socket opened by the web server when it spawns the application.\n" +
+			"\"unix\" indicates that a standard unix socket should be opened.\n" +
+			"    The file name can be specified in the \"filename\" argument or appended to this argument with a colon, eg:\n" +
+			"    unix\n    unix:/tmp/fastcgi-mono-socket\n" +
+			"\"tcp\" indicates that a TCP socket should be opened. " +
+			"    The address and port can be specified in the \"port\" and \"address\" arguments or appended to this argument with a colon, eg:\n" +
+			"    tcp\n    tcp:8081\n    tcp:127.0.0.1:8081\n    tcp:0.0.0.0:8081";
+
+		public const string AppConfigFile = "Adds application definitions from an XML configuration file, typically with the \".webapp\" extension. " +
+			"See sample configuration file that comes with the server.";
+
+		public const string AppConfigDir = "Adds application definitions from all XML files found in the specified directory. " +
+			"Files must have the \".webapp\" extension.";
+
+		public const string ConfigFile = "Specifies a file containing configuration options, identical to those available in the command line.";
+
+		public const string Stoppable = "Allows the user to stop the server by pressing \"Enter\". " +
+			"This should not be used when the server has no controlling terminal.";
+
+		internal const string Address = "Specifies the IP address to listen on.";
+
+		public const string Port = "Specifies the TCP port number to listen on.";
+
+		internal const string Root = "Specifies the root directory the server changes to before doing performing any operations.\n" +
+			"This value is only used when \"appconfigfile\", \"appconfigdir\", or \"applications\" is set, to provide a relative base path.";
+
+		// TODO: use markup (sigh) for better formatting
+		public const string Applications = "Adds applications from a comma separated list of virtual and physical directory pairs. " +
+			"The pairs are separated by colons and optionally include the virtual host name and port to use:\n" +
+			"    [hostname:[port:]]VPath:realpath,...\n" +
+			"Samples:\n" +
+			"     /:.\n" +
+			"    The virtual root directory, \"/\", is mapped to the current directory or \"root\" if specified." +
+			"    /blog:../myblog\n" +
+			"    The virtual /blog is mapped to ../myblog\n" +
+			"    myhost.someprovider.net:/blog:../myblog\n" +
+			"    The virtual /blog at myhost.someprovider.net is mapped to ../myblog.\n" +
+			"    This means that other host names, like \"localhost\" will not be mapped.\n" +
+			"    /:.,/blog:../myblog\n" +
+			"    Two applications like the above ones are handled.\n" +
+			"    *:80:/:standard,*:433:/:secure\n" +
+			"    The server uses different applications on the unsecure and secure ports.";
+
+		public const string Terminate = "Gracefully terminates a running mod-mono-server instance. " +
+			"All other options but --filename or --address and --port are ignored if this option is provided.";
+
+		public const string Master = "This instance will be used to by mod_mono to create ASP.NET applications on demand. " +
+			"If this option is provided, there is no need to provide a list of applications to start.";
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/IHelpConfigurationManager.cs b/src/Mono.WebServer/Options/IHelpConfigurationManager.cs
new file mode 100644
index 0000000..2ce13da
--- /dev/null
+++ b/src/Mono.WebServer/Options/IHelpConfigurationManager.cs
@@ -0,0 +1,37 @@
+//
+// IHelpConfigurationManager.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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 NDesk.Options;
+
+namespace Mono.WebServer.Options {
+	public interface IHelpConfigurationManager {
+		string ProgramName { get; }
+		string Description { get; }
+		OptionSet CreateOptionSet ();
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Options.cs b/src/Mono.WebServer/Options/Options.cs
new file mode 100644
index 0000000..dbd9b27
--- /dev/null
+++ b/src/Mono.WebServer/Options/Options.cs
@@ -0,0 +1,997 @@
+//
+// Options.cs
+//
+// Authors:
+//  Jonathan Pryor <jpryor at novell.com>
+//
+// Copyright (C) 2008 Novell (http://www.novell.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.
+//
+
+//
+// A Getopt::Long-inspired option parsing library for C#.
+//
+// NDesk.Options.OptionSet is built upon a key/value table, where the
+// key is a option format string and the value is a delegate that is 
+// invoked when the format string is matched.
+//
+// Option format strings:
+//  Regex-like BNF Grammar: 
+//    name: .+
+//    type: [=:]
+//    sep: ( [^{}]+ | '{' .+ '}' )?
+//    aliases: ( name type sep ) ( '|' name type sep )*
+// 
+// Each '|'-delimited name is an alias for the associated action.  If the
+// format string ends in a '=', it has a required value.  If the format
+// string ends in a ':', it has an optional value.  If neither '=' or ':'
+// is present, no value is supported.  `=' or `:' need only be defined on one
+// alias, but if they are provided on more than one they must be consistent.
+//
+// Each alias portion may also end with a "key/value separator", which is used
+// to split option values if the option accepts > 1 value.  If not specified,
+// it defaults to '=' and ':'.  If specified, it can be any character except
+// '{' and '}' OR the *string* between '{' and '}'.  If no separator should be
+// used (i.e. the separate values should be distinct arguments), then "{}"
+// should be used as the separator.
+//
+// Options are extracted either from the current option by looking for
+// the option name followed by an '=' or ':', or is taken from the
+// following option IFF:
+//  - The current option does not contain a '=' or a ':'
+//  - The current option requires a value (i.e. not a Option type of ':')
+//
+// The `name' used in the option format string does NOT include any leading
+// option indicator, such as '-', '--', or '/'.  All three of these are
+// permitted/required on any named option.
+//
+// Option bundling is permitted so long as:
+//   - '-' is used to start the option group
+//   - all of the bundled options are a single character
+//   - at most one of the bundled options accepts a value, and the value
+//     provided starts from the next character to the end of the string.
+//
+// This allows specifying '-a -b -c' as '-abc', and specifying '-D name=value'
+// as '-Dname=value'.
+//
+// Option processing is disabled by specifying "--".  All options after "--"
+// are returned by OptionSet.Parse() unchanged and unprocessed.
+//
+// Unprocessed options are returned from OptionSet.Parse().
+//
+// Examples:
+//  int verbose = 0;
+//  OptionSet p = new OptionSet ()
+//    .Add ("v", v => ++verbose)
+//    .Add ("name=|value=", v => Console.WriteLine (v));
+//  p.Parse (new string[]{"-v", "--v", "/v", "-name=A", "/name", "B", "extra"});
+//
+// The above would parse the argument string array, and would invoke the
+// lambda expression three times, setting `verbose' to 3 when complete.  
+// It would also print out "A" and "B" to standard output.
+// The returned array would contain the string "extra".
+//
+// C# 3.0 collection initializers are supported and encouraged:
+//  var p = new OptionSet () {
+//    { "h|?|help", v => ShowHelp () },
+//  };
+//
+// System.ComponentModel.TypeConverter is also supported, allowing the use of
+// custom data types in the callback type; TypeConverter.ConvertFromString()
+// is used to convert the value option to an instance of the specified
+// type:
+//
+//  var p = new OptionSet () {
+//    { "foo=", (Foo f) => Console.WriteLine (f.ToString ()) },
+//  };
+//
+// Random other tidbits:
+//  - Boolean options (those w/o '=' or ':' in the option format string)
+//    are explicitly enabled if they are followed with '+', and explicitly
+//    disabled if they are followed with '-':
+//      string a = null;
+//      var p = new OptionSet () {
+//        { "a", s => a = s },
+//      };
+//      p.Parse (new string[]{"-a"});   // sets a != null
+//      p.Parse (new string[]{"-a+"});  // sets a != null
+//      p.Parse (new string[]{"-a-"});  // sets a == null
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Security.Permissions;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace NDesk.Options {
+
+	public class OptionValueCollection : IList<string> {
+		readonly List<string> values = new List<string> ();
+		readonly OptionContext context;
+
+		internal OptionValueCollection (OptionContext context)
+		{
+			this.context = context;
+		}
+
+		#region ICollection<T>
+		public void Add (string item)                       {values.Add (item);}
+		public void Clear ()                                {values.Clear ();}
+		public bool Contains (string item)                  {return values.Contains (item);}
+		public void CopyTo (string[] array, int arrayIndex) {values.CopyTo (array, arrayIndex);}
+		public bool Remove (string item)                    {return values.Remove (item);}
+		public int Count                                    {get {return values.Count;}}
+		public bool IsReadOnly                              {get {return false;}}
+		#endregion
+
+		#region IEnumerable
+		IEnumerator IEnumerable.GetEnumerator () {return values.GetEnumerator ();}
+		#endregion
+
+		#region IEnumerable<T>
+		public IEnumerator<string> GetEnumerator () {return values.GetEnumerator ();}
+		#endregion
+
+		#region IList<T>
+		public int IndexOf (string item)            {return values.IndexOf (item);}
+		public void Insert (int index, string item) {values.Insert (index, item);}
+		public void RemoveAt (int index)            {values.RemoveAt (index);}
+
+		void AssertValid (int index)
+		{
+			if (context.Option == null)
+				throw new InvalidOperationException ("OptionContext.Option is null.");
+			if (index >= context.Option.MaxValueCount)
+				throw new ArgumentOutOfRangeException ("index");
+			if (context.Option.OptionValueType == OptionValueType.Required &&
+					index >= values.Count)
+				throw new OptionException (String.Format (
+							context.OptionSet.MessageLocalizer ("Missing required value for option '{0}'."), context.OptionName), 
+						context.OptionName);
+		}
+
+		public string this [int index] {
+			get {
+				AssertValid (index);
+				return index >= values.Count ? null : values [index];
+			}
+			set {
+				values [index] = value;
+			}
+		}
+		#endregion
+
+		public List<string> ToList ()
+		{
+			return new List<string> (values);
+		}
+
+		public string[] ToArray ()
+		{
+			return values.ToArray ();
+		}
+
+		public override string ToString ()
+		{
+			return String.Join (", ", values.ToArray ());
+		}
+	}
+
+	public class OptionContext {
+		public OptionContext (OptionSet set)
+		{
+			OptionSet = set;
+			OptionValues = new OptionValueCollection (this);
+		}
+
+		public Option Option { get; set; }
+
+		public string OptionName { get; set; }
+
+		public int OptionIndex { get; set; }
+
+		public OptionSet OptionSet { get; private set; }
+
+		public OptionValueCollection OptionValues { get; private set; }
+	}
+
+	public enum OptionValueType {
+		None, 
+		Optional,
+		Required,
+	}
+
+	public abstract class Option {
+		protected Option (string prototype, string description)
+			: this (prototype, description, 1)
+		{
+		}
+
+		protected Option (string prototype, string description, int maxValueCount)
+		{
+			if (prototype == null)
+				throw new ArgumentNullException ("prototype");
+			if (prototype.Length == 0)
+				throw new ArgumentException ("Cannot be the empty string.", "prototype");
+			if (maxValueCount < 0)
+				throw new ArgumentOutOfRangeException ("maxValueCount");
+
+			Prototype       = prototype;
+			Description     = description;
+			Names           = prototype.Split ('|');
+			MaxValueCount   = maxValueCount;
+			OptionValueType = ParsePrototype ();
+
+			if (MaxValueCount == 0 && OptionValueType != OptionValueType.None)
+				throw new ArgumentException (
+						"Cannot provide maxValueCount of 0 for OptionValueType.Required or " +
+							"OptionValueType.Optional.",
+						"maxValueCount");
+			if (OptionValueType == OptionValueType.None && maxValueCount > 1)
+				throw new ArgumentException (
+						String.Format ("Cannot provide maxValueCount of {0} for OptionValueType.None.", maxValueCount),
+						"maxValueCount");
+			if (Array.IndexOf (Names, "<>") >= 0 && 
+					((Names.Length == 1 && OptionValueType != OptionValueType.None) ||
+					 (Names.Length > 1 && MaxValueCount > 1)))
+				throw new ArgumentException (
+						"The default option handler '<>' cannot require values.",
+						"prototype");
+		}
+
+		public string Prototype { get; private set; }
+		public string Description { get; private set; }
+		public OptionValueType OptionValueType { get; private set; }
+		public int MaxValueCount { get; private set; }
+
+		public string[] GetNames ()
+		{
+			return (string[]) Names.Clone ();
+		}
+
+		public string[] GetValueSeparators ()
+		{
+			if (ValueSeparators == null)
+				return new string [0];
+			return (string[]) ValueSeparators.Clone ();
+		}
+
+		protected static T Parse<T> (string value, OptionContext c)
+		{
+			TypeConverter conv = TypeDescriptor.GetConverter (typeof (T));
+			T t = default (T);
+			try {
+				if (value != null)
+					t = (T) conv.ConvertFromString (value);
+			}
+			catch (Exception e) {
+				throw new OptionException (
+						String.Format (
+							c.OptionSet.MessageLocalizer ("Could not convert string `{0}' to type {1} for option `{2}'."),
+							value, typeof (T).Name, c.OptionName),
+						c.OptionName, e);
+			}
+			return t;
+		}
+
+		internal string[] Names { get; private set; }
+		internal string[] ValueSeparators { get; private set; }
+
+		static readonly char[] nameTerminator = {'=', ':'};
+
+		OptionValueType ParsePrototype ()
+		{
+			char type = '\0';
+			var seps = new List<string> ();
+			for (int i = 0; i < Names.Length; ++i) {
+				string name = Names [i];
+				if (name.Length == 0)
+					throw new ArgumentException ("Empty option names are not supported.");
+
+				int end = name.IndexOfAny (nameTerminator);
+				if (end == -1)
+					continue;
+				Names [i] = name.Substring (0, end);
+				if (type == '\0' || type == name [end])
+					type = name [end];
+				else 
+					throw new ArgumentException (
+							String.Format ("Conflicting option types: '{0}' vs. '{1}'.", type, name [end]));
+				AddSeparators (name, end, seps);
+			}
+
+			if (type == '\0')
+				return OptionValueType.None;
+
+			if (MaxValueCount <= 1 && seps.Count != 0)
+				throw new ArgumentException (
+						String.Format ("Cannot provide key/value separators for Options taking {0} value(s).", MaxValueCount));
+			if (MaxValueCount > 1) {
+				if (seps.Count == 0)
+					ValueSeparators = new[]{":", "="};
+				else if (seps.Count == 1 && seps [0].Length == 0)
+					ValueSeparators = null;
+				else
+					ValueSeparators = seps.ToArray ();
+			}
+
+			return type == '=' ? OptionValueType.Required : OptionValueType.Optional;
+		}
+
+		static void AddSeparators (string name, int end, ICollection<string> seps)
+		{
+			int start = -1;
+			for (int i = end+1; i < name.Length; ++i) {
+				switch (name [i]) {
+					case '{':
+						if (start != -1)
+							throw new ArgumentException (
+									String.Format ("Ill-formed name/value separator found in \"{0}\".", name),
+									"name");
+						start = i+1;
+						break;
+					case '}':
+						if (start == -1)
+							throw new ArgumentException (
+									String.Format ("Ill-formed name/value separator found in \"{0}\".", name),
+									"name");
+						seps.Add (name.Substring (start, i-start));
+						start = -1;
+						break;
+					default:
+						if (start == -1)
+							seps.Add (name [i].ToString ());
+						break;
+				}
+			}
+			if (start != -1)
+				throw new ArgumentException (
+						String.Format ("Ill-formed name/value separator found in \"{0}\".", name),
+						"name");
+		}
+
+		public void Invoke (OptionContext c)
+		{
+			OnParseComplete (c);
+			c.OptionName  = null;
+			c.Option      = null;
+			c.OptionValues.Clear ();
+		}
+
+		protected abstract void OnParseComplete (OptionContext c);
+
+		public override string ToString ()
+		{
+			return Prototype;
+		}
+	}
+
+	[Serializable]
+	public class OptionException : Exception {
+		public OptionException ()
+		{
+		}
+
+		public OptionException (string message, string optionName)
+			: base (message)
+		{
+			OptionName = optionName;
+		}
+
+		public OptionException (string message, string optionName, Exception innerException)
+			: base (message, innerException)
+		{
+			OptionName = optionName;
+		}
+
+		protected OptionException (SerializationInfo info, StreamingContext context)
+			: base (info, context)
+		{
+			OptionName = info.GetString ("OptionName");
+		}
+
+		public string OptionName { get; private set; }
+
+		[SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
+		public override void GetObjectData (SerializationInfo info, StreamingContext context)
+		{
+			base.GetObjectData (info, context);
+			info.AddValue ("OptionName", OptionName);
+		}
+	}
+
+	public delegate void OptionAction<in TKey, in TValue> (TKey key, TValue value);
+
+	public class OptionSet : KeyedCollection<string, Option>
+	{
+		public OptionSet ()
+			: this (f => f)
+		{
+		}
+
+		public OptionSet (Converter<string, string> localizer)
+		{
+			MessageLocalizer = localizer;
+		}
+
+		public Converter<string, string> MessageLocalizer { get; private set; }
+
+		protected override string GetKeyForItem (Option item)
+		{
+			if (item == null)
+				throw new ArgumentNullException ("item");
+			if (item.Names != null && item.Names.Length > 0)
+				return item.Names [0];
+			// This should never happen, as it's invalid for Option to be
+			// constructed w/o any names.
+			throw new InvalidOperationException ("Option has no names!");
+		}
+
+		[Obsolete ("Use KeyedCollection.this[string]")]
+		protected Option GetOptionForName (string option)
+		{
+			if (option == null)
+				throw new ArgumentNullException ("option");
+			try {
+				return base [option];
+			}
+			catch (KeyNotFoundException) {
+				return null;
+			}
+		}
+
+		protected override void InsertItem (int index, Option item)
+		{
+			base.InsertItem (index, item);
+			AddImpl (item);
+		}
+
+		protected override void RemoveItem (int index)
+		{
+			base.RemoveItem (index);
+			Option p = Items [index];
+			// KeyedCollection.RemoveItem() handles the 0th item
+			for (int i = 1; i < p.Names.Length; ++i) {
+				Dictionary.Remove (p.Names [i]);
+			}
+		}
+
+		protected override void SetItem (int index, Option item)
+		{
+			base.SetItem (index, item);
+			RemoveItem (index);
+			AddImpl (item);
+		}
+
+		void AddImpl (Option option)
+		{
+			if (option == null)
+				throw new ArgumentNullException ("option");
+			var added = new List<string> (option.Names.Length);
+			try {
+				// KeyedCollection.InsertItem/SetItem handle the 0th name.
+				for (int i = 1; i < option.Names.Length; ++i) {
+					Dictionary.Add (option.Names [i], option);
+					added.Add (option.Names [i]);
+				}
+			}
+			catch (Exception) {
+				foreach (string name in added)
+					Dictionary.Remove (name);
+				throw;
+			}
+		}
+
+		public new OptionSet Add (Option option)
+		{
+			base.Add (option);
+			return this;
+		}
+
+		sealed class ActionOption : Option {
+			readonly Action<OptionValueCollection> action;
+
+			public ActionOption (string prototype, string description, int count, Action<OptionValueCollection> action)
+				: base (prototype, description, count)
+			{
+				if (action == null)
+					throw new ArgumentNullException ("action");
+				this.action = action;
+			}
+
+			protected override void OnParseComplete (OptionContext c)
+			{
+				action (c.OptionValues);
+			}
+		}
+
+		public OptionSet Add (string prototype, Action<string> action)
+		{
+			return Add (prototype, null, action);
+		}
+
+		public OptionSet Add (string prototype, string description, Action<string> action)
+		{
+			if (action == null)
+				throw new ArgumentNullException ("action");
+			Option p = new ActionOption (prototype, description, 1,
+				v => action (v [0]));
+			base.Add (p);
+			return this;
+		}
+
+		public OptionSet Add (string prototype, OptionAction<string, string> action)
+		{
+			return Add (prototype, null, action);
+		}
+
+		public OptionSet Add (string prototype, string description, OptionAction<string, string> action)
+		{
+			if (action == null)
+				throw new ArgumentNullException ("action");
+			Option p = new ActionOption (prototype, description, 2,
+				v => action (v [0], v [1]));
+			base.Add (p);
+			return this;
+		}
+
+		sealed class ActionOption<T> : Option {
+			readonly Action<T> action;
+
+			public ActionOption (string prototype, string description, Action<T> action)
+				: base (prototype, description, 1)
+			{
+				if (action == null)
+					throw new ArgumentNullException ("action");
+				this.action = action;
+			}
+
+			protected override void OnParseComplete (OptionContext c)
+			{
+				action (Parse<T> (c.OptionValues [0], c));
+			}
+		}
+
+		sealed class ActionOption<TKey, TValue> : Option {
+			readonly OptionAction<TKey, TValue> action;
+
+			public ActionOption (string prototype, string description, OptionAction<TKey, TValue> action)
+				: base (prototype, description, 2)
+			{
+				if (action == null)
+					throw new ArgumentNullException ("action");
+				this.action = action;
+			}
+
+			protected override void OnParseComplete (OptionContext c)
+			{
+				action (
+					Parse<TKey> (c.OptionValues [0], c),
+					Parse<TValue> (c.OptionValues [1], c));
+			}
+		}
+
+		public OptionSet Add<T> (string prototype, Action<T> action)
+		{
+			return Add (prototype, null, action);
+		}
+
+		public OptionSet Add<T> (string prototype, string description, Action<T> action)
+		{
+			return Add (new ActionOption<T> (prototype, description, action));
+		}
+
+		public OptionSet Add<TKey, TValue> (string prototype, OptionAction<TKey, TValue> action)
+		{
+			return Add (prototype, null, action);
+		}
+
+		public OptionSet Add<TKey, TValue> (string prototype, string description, OptionAction<TKey, TValue> action)
+		{
+			return Add (new ActionOption<TKey, TValue> (prototype, description, action));
+		}
+
+		protected virtual OptionContext CreateOptionContext ()
+		{
+			return new OptionContext (this);
+		}
+
+		public List<string> Parse (IEnumerable<string> arguments)
+		{
+			OptionContext c = CreateOptionContext ();
+			c.OptionIndex = -1;
+			bool process = true;
+			var unprocessed = new List<string> ();
+			Option def = Contains ("<>") ? this ["<>"] : null;
+			foreach (string argument in arguments) {
+				++c.OptionIndex;
+				if (argument == "--") {
+					process = false;
+					continue;
+				}
+				if (!process) {
+					Unprocessed (unprocessed, def, c, argument);
+					continue;
+				}
+				if (!Parse (argument, c))
+					Unprocessed (unprocessed, def, c, argument);
+			}
+			if (c.Option != null)
+				c.Option.Invoke (c);
+			return unprocessed;
+		}
+
+		static void Unprocessed (ICollection<string> extra, Option def, OptionContext c, string argument)
+		{
+			if (def == null) {
+				extra.Add (argument);
+				return;
+			}
+			c.OptionValues.Add (argument);
+			c.Option = def;
+			c.Option.Invoke (c);
+		}
+
+		readonly Regex valueOption = new Regex (
+			@"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$");
+
+		protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)
+		{
+			if (argument == null)
+				throw new ArgumentNullException ("argument");
+
+			flag = name = sep = value = null;
+			Match m = valueOption.Match (argument);
+			if (!m.Success) {
+				return false;
+			}
+			flag  = m.Groups ["flag"].Value;
+			name  = m.Groups ["name"].Value;
+			if (m.Groups ["sep"].Success && m.Groups ["value"].Success) {
+				sep   = m.Groups ["sep"].Value;
+				value = m.Groups ["value"].Value;
+			}
+			return true;
+		}
+
+		protected virtual bool Parse (string argument, OptionContext c)
+		{
+			if (c.Option != null) {
+				ParseValue (argument, c);
+				return true;
+			}
+
+			string f, n, s, v;
+			if (!GetOptionParts (argument, out f, out n, out s, out v))
+				return false;
+
+			if (Contains (n)) {
+				Option p = this [n];
+				c.OptionName = f + n;
+				c.Option     = p;
+				switch (p.OptionValueType) {
+					case OptionValueType.None:
+						c.OptionValues.Add (n);
+						c.Option.Invoke (c);
+						break;
+					case OptionValueType.Optional:
+					case OptionValueType.Required: 
+						ParseValue (v, c);
+						break;
+				}
+				return true;
+			}
+			// no match; is it a bool option?
+			if (ParseBool (argument, n, c))
+				return true;
+			// is it a bundled option?
+			if (ParseBundledValue (f, String.Concat (n, s, v), c))
+				return true;
+
+			return false;
+		}
+
+		void ParseValue (string option, OptionContext c)
+		{
+			if (option != null)
+				foreach (string o in c.Option.ValueSeparators != null 
+						? option.Split (c.Option.ValueSeparators, StringSplitOptions.None)
+						: new[]{option}) {
+					c.OptionValues.Add (o);
+				}
+			if (c.OptionValues.Count == c.Option.MaxValueCount || 
+					c.Option.OptionValueType == OptionValueType.Optional)
+				c.Option.Invoke (c);
+			else if (c.OptionValues.Count > c.Option.MaxValueCount) {
+				throw new OptionException (MessageLocalizer (String.Format (
+								"Error: Found {0} option values when expecting {1}.", 
+								c.OptionValues.Count, c.Option.MaxValueCount)),
+						c.OptionName);
+			}
+		}
+
+		bool ParseBool (string option, string n, OptionContext c)
+		{
+			string rn;
+			if (n.Length >= 1 && (n [n.Length-1] == '+' || n [n.Length-1] == '-') &&
+					Contains ((rn = n.Substring (0, n.Length-1)))) {
+				Option p = this [rn];
+				string v = n [n.Length-1] == '+' ? option : null;
+				c.OptionName  = option;
+				c.Option      = p;
+				c.OptionValues.Add (v);
+				p.Invoke (c);
+				return true;
+			}
+			return false;
+		}
+
+		bool ParseBundledValue (string f, string n, OptionContext c)
+		{
+			if (f != "-")
+				return false;
+			for (int i = 0; i < n.Length; ++i) {
+				string opt = f + n [i];
+				string rn = n [i].ToString ();
+				if (!Contains (rn)) {
+					if (i == 0)
+						return false;
+					throw new OptionException (String.Format (MessageLocalizer (
+									"Cannot bundle unregistered option '{0}'."), opt), opt);
+				}
+				Option p = this [rn];
+				switch (p.OptionValueType) {
+					case OptionValueType.None:
+						Invoke (c, opt, n, p);
+						break;
+					case OptionValueType.Optional:
+					case OptionValueType.Required: {
+						string v     = n.Substring (i+1);
+						c.Option     = p;
+						c.OptionName = opt;
+						ParseValue (v.Length != 0 ? v : null, c);
+						return true;
+					}
+					default:
+						throw new InvalidOperationException ("Unknown OptionValueType: " + p.OptionValueType);
+				}
+			}
+			return true;
+		}
+
+		static void Invoke (OptionContext c, string name, string value, Option option)
+		{
+			c.OptionName  = name;
+			c.Option      = option;
+			c.OptionValues.Add (value);
+			option.Invoke (c);
+		}
+
+		const int OPTION_WIDTH = 29;
+
+		public void WriteOptionDescriptions (TextWriter o)
+		{
+			foreach (Option p in this) {
+				int written = 0;
+				if (!WriteOptionPrototype (o, p, ref written))
+					continue;
+
+				if (written < OPTION_WIDTH)
+					o.Write (new string (' ', OPTION_WIDTH - written));
+				else {
+					o.WriteLine ();
+					o.Write (new string (' ', OPTION_WIDTH));
+				}
+
+				List<string> lines = GetLines (MessageLocalizer (GetDescription (p.Description)));
+				o.WriteLine (lines [0]);
+				var prefix = new string (' ', OPTION_WIDTH+2);
+				for (int i = 1; i < lines.Count; ++i) {
+					o.Write (prefix);
+					o.WriteLine (lines [i]);
+				}
+			}
+		}
+
+		bool WriteOptionPrototype (TextWriter o, Option p, ref int written)
+		{
+			string[] names = p.Names;
+
+			int i = GetNextOptionIndex (names, 0);
+			if (i == names.Length)
+				return false;
+
+			if (names [i].Length == 1) {
+				Write (o, ref written, "  -");
+				Write (o, ref written, names [0]);
+			}
+			else {
+				Write (o, ref written, "      --");
+				Write (o, ref written, names [0]);
+			}
+
+			for ( i = GetNextOptionIndex (names, i+1); 
+					i < names.Length; i = GetNextOptionIndex (names, i+1)) {
+				Write (o, ref written, ", ");
+				Write (o, ref written, names [i].Length == 1 ? "-" : "--");
+				Write (o, ref written, names [i]);
+			}
+
+			if (p.OptionValueType == OptionValueType.Optional ||
+					p.OptionValueType == OptionValueType.Required) {
+				if (p.OptionValueType == OptionValueType.Optional) {
+					Write (o, ref written, MessageLocalizer ("["));
+				}
+				Write (o, ref written, MessageLocalizer ("=" + GetArgumentName (0, p.MaxValueCount, p.Description)));
+				string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0 
+					? p.ValueSeparators [0]
+					: " ";
+				for (int c = 1; c < p.MaxValueCount; ++c) {
+					Write (o, ref written, MessageLocalizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description)));
+				}
+				if (p.OptionValueType == OptionValueType.Optional) {
+					Write (o, ref written, MessageLocalizer ("]"));
+				}
+			}
+			return true;
+		}
+
+		static int GetNextOptionIndex (string[] names, int i)
+		{
+			while (i < names.Length && names [i] == "<>") {
+				++i;
+			}
+			return i;
+		}
+
+		static void Write (TextWriter o, ref int n, string s)
+		{
+			n += s.Length;
+			o.Write (s);
+		}
+
+		static string GetArgumentName (int index, int maxIndex, string description)
+		{
+			if (String.IsNullOrEmpty (description))
+				return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
+			string[] nameStart = maxIndex == 1
+				? new[] { "{0:", "{" }
+				: new[] { "{" + index + ":" };
+			foreach (string name in nameStart) {
+				int start, j = 0;
+				do {
+					start = description.IndexOf (name, j);
+				} while (start >= 0 && j != 0 && description [j++ - 1] == '{');
+				if (start == -1)
+					continue;
+				int end = description.IndexOf ("}", start);
+				if (end == -1)
+					continue;
+				return description.Substring (start + name.Length, end - start - name.Length);
+			}
+			return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
+		}
+
+		static string GetDescription (string description)
+		{
+			if (String.IsNullOrEmpty (description))
+				return String.Empty;
+			var sb = new StringBuilder (description.Length);
+			int start = -1;
+			for (int i = 0; i < description.Length; ++i) {
+				switch (description [i]) {
+					case '{':
+						if (i == start) {
+							sb.Append ('{');
+							start = -1;
+						}
+						else if (start < 0)
+							start = i + 1;
+						break;
+					case '}':
+						if (start < 0) {
+							if ((i+1) == description.Length || description [i+1] != '}')
+								throw new InvalidOperationException ("Invalid option description: " + description);
+							++i;
+							sb.Append ("}");
+						}
+						else {
+							sb.Append (description.Substring (start, i - start));
+							start = -1;
+						}
+						break;
+					case ':':
+						if (start < 0)
+							goto default;
+						start = i + 1;
+						break;
+					default:
+						if (start < 0)
+							sb.Append (description [i]);
+						break;
+				}
+			}
+			return sb.ToString ();
+		}
+
+		static List<string> GetLines (string description)
+		{
+			var lines = new List<string> ();
+			if (String.IsNullOrEmpty (description)) {
+				lines.Add (String.Empty);
+				return lines;
+			}
+			const int length = 80 - OPTION_WIDTH - 2;
+			int start = 0, end;
+			do {
+				end = GetLineEnd (start, length, description);
+				bool cont = false;
+				if (end < description.Length) {
+					char c = description [end];
+					if (c == '-' || (char.IsWhiteSpace (c) && c != '\n'))
+						++end;
+					else if (c != '\n') {
+						cont = true;
+						--end;
+					}
+				}
+				lines.Add (description.Substring (start, end - start));
+				if (cont) {
+					lines [lines.Count-1] += "-";
+				}
+				start = end;
+				if (start < description.Length && description [start] == '\n')
+					++start;
+			} while (end < description.Length);
+			return lines;
+		}
+
+		static int GetLineEnd (int start, int length, string description)
+		{
+			int end = Math.Min (start + length, description.Length);
+			int sep = -1;
+			for (int i = start; i < end; ++i) {
+				switch (description [i]) {
+					case ' ':
+					case '\t':
+					case '\v':
+					case '-':
+					case ',':
+					case '.':
+					case ';':
+						sep = i;
+						break;
+					case '\n':
+						return i;
+				}
+			}
+			if (sep == -1 || end == description.Length)
+				return end;
+			return sep;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/ServerConfigurationManager.cs b/src/Mono.WebServer/Options/ServerConfigurationManager.cs
new file mode 100644
index 0000000..15fa05b
--- /dev/null
+++ b/src/Mono.WebServer/Options/ServerConfigurationManager.cs
@@ -0,0 +1,78 @@
+//
+// ServerConfigurationManager.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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 Mono.WebServer.Options.Settings;
+
+namespace Mono.WebServer.Options {
+	public abstract class ServerConfigurationManager : ConfigurationManager, IHelpConfigurationManager
+	{
+		#region Backing fields
+		protected readonly StringSetting root = new StringSetting ("root", Descriptions.Root, "MonoServerRootDir", "MONO_ROOT|MONO_FCGI_ROOT", Environment.CurrentDirectory);
+		readonly StringSetting applications = new StringSetting ("applications", Descriptions.Applications, "MonoApplications", "MONO_APPLICATIONS|MONO_FCGI_APPLICATIONS");
+		readonly StringSetting appConfigFile = new StringSetting ("appconfigfile", Descriptions.AppConfigFile, "MonoApplicationsConfigFile", "MONO_APPCONFIGFILE|MONO_FCGI_APPCONFIGFILE");
+		readonly StringSetting appConfigDir = new StringSetting ("appconfigdir", Descriptions.AppConfigDir, "MonoApplicationsConfigDir", "MONO_APPCONFIGDIR|MONO_FCGI_APPCONFIGDIR");
+
+		readonly UInt32Setting backlog = new UInt32Setting ("backlog", "The listen backlog.", defaultValue: 500);
+
+		protected readonly Setting<IPAddress> address = new Setting<IPAddress> ("address", IPAddress.TryParse, Descriptions.Address, "MonoServerAddress", "MONO_ADDRESS|MONO_FCGI_ADDRESS", IPAddress.Loopback);
+		#endregion
+
+		#region Typesafe properties
+		public string Root {
+			get { return root; }
+		}
+		public string Applications {
+			get { return applications; }
+		}
+		public string AppConfigFile {
+			get { return appConfigFile; }
+		}
+		public string AppConfigDir {
+			get { return appConfigDir; }
+		}
+
+		public uint Backlog {
+			get { return backlog; }
+		}
+
+		public IPAddress Address { get { return address; } }
+		#endregion
+
+		public abstract string ProgramName { get; }
+		public abstract string Description { get; }
+
+		protected ServerConfigurationManager (string name) : base (name)
+		{
+			Add (root, applications, appConfigFile, appConfigDir,
+				backlog,
+				address);
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/Settings/BoolSetting.cs b/src/Mono.WebServer/Options/Settings/BoolSetting.cs
new file mode 100644
index 0000000..153f0cc
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/BoolSetting.cs
@@ -0,0 +1,39 @@
+//
+// BoolSetting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class BoolSetting : Setting<bool>
+	{
+		public BoolSetting (string name, string description, string appSetting = null, string environment = null, bool defaultValue = false, string prototype = null)
+			: base (name, Boolean.TryParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/EnumSetting.cs b/src/Mono.WebServer/Options/Settings/EnumSetting.cs
new file mode 100644
index 0000000..94c8c8b
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/EnumSetting.cs
@@ -0,0 +1,50 @@
+//
+// EnumSetting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class EnumSetting<T> : Setting<T> where T : struct 
+	{
+		static bool EnumParser<TEnum> (string input, out TEnum output)
+		{
+			output = default (TEnum);
+			try {
+				output = (TEnum)Enum.Parse (typeof (TEnum), input, true);
+				return true;
+			} catch (ArgumentException) { // TODO: catch more specific type
+				return false;
+			}
+		}
+
+		public EnumSetting (string name, string description, string appSetting = null, string environment = null, T defaultValue = default(T), string prototype = null)
+			: base (name, EnumParser, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/Settings/ISetting.cs b/src/Mono.WebServer/Options/Settings/ISetting.cs
new file mode 100644
index 0000000..0bf2b54
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/ISetting.cs
@@ -0,0 +1,44 @@
+//
+// ISetting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public interface ISetting
+	{
+		string Name { get; }
+		string Description { get; }
+		string AppSetting { get; }
+		string Environment { get; }
+		string Prototype { get; }
+		[Obsolete]
+		object Value { get; }
+
+		void MaybeParseUpdate (SettingSource settingSource, string value);
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/Int32Setting.cs b/src/Mono.WebServer/Options/Settings/Int32Setting.cs
new file mode 100644
index 0000000..fa637f6
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/Int32Setting.cs
@@ -0,0 +1,39 @@
+//
+// Int32Setting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class Int32Setting : Setting<int>
+	{
+		public Int32Setting (string name, string description, string appSetting = null, string environment = null, int defaultValue = default(Int32), string prototype = null)
+			: base (name, Int32.TryParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/NullableInt32Setting.cs b/src/Mono.WebServer/Options/Settings/NullableInt32Setting.cs
new file mode 100644
index 0000000..aca41d3
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/NullableInt32Setting.cs
@@ -0,0 +1,39 @@
+//
+// NullableInt32Setting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class NullableInt32Setting : NullableSetting<int>
+	{
+		public NullableInt32Setting (string name, string description, string appSetting = null, string environment = null, int? defaultValue = null, string prototype = null)
+			: base (name, Int32.TryParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/NullableSetting.cs b/src/Mono.WebServer/Options/Settings/NullableSetting.cs
new file mode 100644
index 0000000..5a27965
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/NullableSetting.cs
@@ -0,0 +1,51 @@
+//
+// NullableSetting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.
+//
+
+namespace Mono.WebServer.Options.Settings {
+	public class NullableSetting<T>:Setting<T?> where T : struct
+	{
+		public NullableSetting (string name, Parser<T> parser, string description, string appSetting = null, string environment = null, T? defaultValue = null, string prototype = null)
+			: base (name, ToNullable(parser), description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+
+		static Parser<T?> ToNullable (Parser<T> parser)
+		{
+			return delegate (string input, out T? output)
+			{
+				T temp;
+				if (!parser (input, out temp)) {
+					output = null;
+					return false;
+				}
+				output = temp;
+				return true;
+			};
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Options/Settings/NullableUInt16Setting.cs b/src/Mono.WebServer/Options/Settings/NullableUInt16Setting.cs
new file mode 100644
index 0000000..2f367c1
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/NullableUInt16Setting.cs
@@ -0,0 +1,39 @@
+//
+// NullableUInt16Setting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class NullableUInt16Setting : NullableSetting<ushort>
+	{
+		public NullableUInt16Setting (string name, string description, string appSetting = null, string environment = null, ushort? defaultValue = null, string prototype = null)
+			: base (name, UInt16.TryParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/Parser.cs b/src/Mono.WebServer/Options/Settings/Parser.cs
new file mode 100644
index 0000000..dc6ef19
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/Parser.cs
@@ -0,0 +1,31 @@
+//
+// Parser.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.
+//
+
+namespace Mono.WebServer.Options.Settings {
+	public delegate bool Parser<T> (string input, out T output);
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/Setting.cs b/src/Mono.WebServer/Options/Settings/Setting.cs
new file mode 100644
index 0000000..aebd5fa
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/Setting.cs
@@ -0,0 +1,95 @@
+//
+// Settings.cs.
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialene at gmail.com>
+//
+// Copyright (C) 2013 Leonardo Taglialegne
+// 
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class Setting<T> : ISetting
+	{
+		// TODO: Find a clean way to make this static
+		readonly Parser<T> parser;
+
+		public Setting (string name, Parser<T> parser, string description, string appSetting = null,
+			string environment = null, T defaultValue = default (T), string prototype = null)
+		{
+			Prototype = prototype ?? name;
+			Description = description;
+			AppSetting = appSetting;
+			Environment = environment;
+			Name = name;
+			this.parser = parser;
+			Value = defaultValue;
+			if (!String.IsNullOrEmpty (environment))
+				foreach (string envVar in environment.Split ('|')) {
+					string value = System.Environment.GetEnvironmentVariable (envVar);
+					MaybeParseUpdate (SettingSource.Environment, value);
+				}
+
+			if (!String.IsNullOrEmpty (appSetting))
+				foreach (var appSett in appSetting.Split ('|')) {
+					string value = System.Configuration.ConfigurationManager.AppSettings [appSett];
+					MaybeParseUpdate (SettingSource.AppSettings, value);
+				}
+		}
+
+		public void MaybeParseUpdate (SettingSource settingSource, string value)
+		{
+			if (value == null)
+				return;
+			T result;
+			if (parser (value, out result))
+				MaybeUpdate (settingSource, result);
+		}
+
+		public bool MaybeUpdate (SettingSource source, T value)
+		{
+			if (source < this.source)
+				return false;
+			Value = value;
+			this.source = source;
+			return true;
+		}
+
+		public static implicit operator T (Setting<T> setting)
+		{
+			return setting.Value;
+		}
+
+		SettingSource source = SettingSource.Default;
+		public string Name { get; private set; }
+		public string Prototype { get; private set; }
+		public string Environment { get; private set; }
+		public string AppSetting { get; private set; }
+		public string Description { get; private set; }
+		public T Value { get; private set; }
+		[Obsolete]
+		object ISetting.Value {
+			get { return Value; }
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/SettingSource.cs b/src/Mono.WebServer/Options/Settings/SettingSource.cs
new file mode 100644
index 0000000..bc6ea9b
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/SettingSource.cs
@@ -0,0 +1,38 @@
+//
+// SettingSource.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.
+//
+
+namespace Mono.WebServer.Options.Settings {
+	public enum SettingSource 
+	{
+		Default,
+		AppSettings,
+		Environment,
+		Xml,
+		CommandLine
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/SettingsCollection.cs b/src/Mono.WebServer/Options/Settings/SettingsCollection.cs
new file mode 100644
index 0000000..e5ff776
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/SettingsCollection.cs
@@ -0,0 +1,38 @@
+//
+// SettingsCollection.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.Collections.ObjectModel;
+
+namespace Mono.WebServer.Options.Settings {
+	public sealed class SettingsCollection : KeyedCollection<string, ISetting> {
+		protected override string GetKeyForItem (ISetting item)
+		{
+			return item.Name;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/StringSetting.cs b/src/Mono.WebServer/Options/Settings/StringSetting.cs
new file mode 100644
index 0000000..06286a5
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/StringSetting.cs
@@ -0,0 +1,45 @@
+//
+// StringSetting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class StringSetting : Setting<string>
+	{
+		public StringSetting (string name, string description, string appSetting = null, string environment = null, string defaultValue = null, string prototype = null)
+			: base (name, FakeParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+
+		static bool FakeParse (string value, out string result)
+		{
+			result = value;
+			return !String.IsNullOrEmpty (value);
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/UInt16Setting.cs b/src/Mono.WebServer/Options/Settings/UInt16Setting.cs
new file mode 100644
index 0000000..fdb4b98
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/UInt16Setting.cs
@@ -0,0 +1,39 @@
+//
+// UInt16Setting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class UInt16Setting : Setting<ushort>
+	{
+		public UInt16Setting (string name, string description, string appSetting = null, string environment = null, ushort defaultValue = default(UInt16), string prototype = null)
+			: base (name, UInt16.TryParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Options/Settings/UInt32Setting.cs b/src/Mono.WebServer/Options/Settings/UInt32Setting.cs
new file mode 100644
index 0000000..55a05de
--- /dev/null
+++ b/src/Mono.WebServer/Options/Settings/UInt32Setting.cs
@@ -0,0 +1,39 @@
+//
+// UInt32Setting.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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;
+
+namespace Mono.WebServer.Options.Settings {
+	public class UInt32Setting : Setting<uint>
+	{
+		public UInt32Setting (string name, string description, string appSetting = null, string environment = null, uint defaultValue = default(UInt32), string prototype = null)
+			: base (name, UInt32.TryParse, description, appSetting, environment, defaultValue, prototype)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/Mono.WebServer/Paths.cs b/src/Mono.WebServer/Paths.cs
new file mode 100644
index 0000000..7055f8b
--- /dev/null
+++ b/src/Mono.WebServer/Paths.cs
@@ -0,0 +1,85 @@
+//
+// Paths.cs
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// Copyright (c) Copyright 2002-2007 Novell, Inc
+//
+// 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.Web;
+using System.Web.Hosting;
+
+namespace Mono.WebServer
+{
+	public static class Paths
+	{
+		public static void GetPathsFromUri (IApplicationHost appHost, string verb, string uri, out string realUri, out string pathInfo)
+		{
+			// There's a hidden missing feature here... :)
+			realUri = uri; pathInfo = String.Empty;
+			string vpath = HttpRuntime.AppDomainAppVirtualPath;
+			int vpathLen = vpath.Length;
+			
+			if (vpath [vpathLen - 1] != '/')
+				vpath += '/';
+
+			if (vpathLen > uri.Length)
+				return;
+
+			uri = uri.Substring (vpathLen);
+			while (uri.Length > 0 && uri [0] == '/')
+				uri = uri.Substring (1);
+
+			int lastSlash = uri.Length;
+
+			for (int dot = uri.LastIndexOf ('.'); dot > 0; dot = uri.LastIndexOf ('.', dot - 1)) {
+				int slash = uri.IndexOf ('/', dot);
+				
+				if (slash == -1)
+					slash = lastSlash;
+				
+				string partial = uri.Substring (0, slash);
+				lastSlash = slash;
+
+				if (!VirtualPathExists (appHost, verb, partial))
+					continue;
+				
+				realUri = vpath + uri.Substring (0, slash);
+				pathInfo = uri.Substring (slash);
+				break;
+			}
+		}
+
+		static bool VirtualPathExists (IApplicationHost appHost, string verb, string uri)
+		{
+			if (appHost.IsHttpHandler (verb, uri))
+				return true;
+
+			VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
+			return vpp != null && vpp.FileExists ("/" + uri);
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Platform.cs b/src/Mono.WebServer/Platform.cs
new file mode 100644
index 0000000..fa10ebb
--- /dev/null
+++ b/src/Mono.WebServer/Platform.cs
@@ -0,0 +1,143 @@
+//
+// Platform.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.IO;
+using Mono.Unix;
+using Mono.Unix.Native;
+using Mono.WebServer.Log;
+
+namespace Mono.WebServer {
+	public static class Platform
+	{
+		public static readonly FinePlatformID Value;
+
+		public static string Name {
+			get { return Value.ToString (); }
+		}
+		
+		public static bool IsUnix {
+			get {
+				var platform = Environment.OSVersion.Platform;
+				return platform == PlatformID.Unix || platform == PlatformID.MacOSX || platform == (PlatformID)128;
+			}
+		}
+
+		static Platform() {
+			Value = GetPlatformId();
+		}
+
+		static FinePlatformID GetPlatformId() {
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Unix:
+				case (PlatformID)128:
+					// Well, there are chances MacOSX is reported as Unix instead of MacOSX.
+					// Instead of platform check, we'll do a feature checks (Mac specific root folders)
+					if (Directory.Exists("/Applications")
+					   && Directory.Exists("/System")
+					   && Directory.Exists("/Users")
+					   && Directory.Exists("/Volumes"))
+						return FinePlatformID.MacOSX;
+					return FinePlatformID.Linux;
+
+				case PlatformID.MacOSX:
+					return FinePlatformID.MacOSX;
+
+				default:
+					return FinePlatformID.Windows;
+			}
+		}
+
+		static uint GetUid (string user)
+		{
+			var info = new UnixUserInfo (user);
+			long uid = info.UserId;
+			if (uid > UInt32.MaxValue || uid <= 0)
+				throw new ArgumentOutOfRangeException ("user", String.Format ("Uid for {0} ({1}) not in range for suid", user, uid));
+			return (uint)uid;
+		}
+
+		static uint GetGid (string group)
+		{
+			var info = new UnixGroupInfo (group);
+			var gid = info.GroupId;
+			if (gid > UInt32.MaxValue || gid <= 0)
+				throw new ArgumentOutOfRangeException ("group", String.Format ("Gid for {0} ({1}) not in range for sgid", group, gid));
+			return (uint)gid;
+		}
+
+		static void SetUser (string user)
+		{
+			Syscall.setuid (GetUid (user));
+		}
+
+		static void SetGroup (string group)
+		{
+			Syscall.setgid (GetGid (group));
+		}
+
+		public static void LogIdentity ()
+		{
+			Logger.Write (LogLevel.Debug, "Uid {0}, euid {1}, gid {2}, egid {3}", Syscall.getuid (), Syscall.geteuid (), Syscall.getgid (), Syscall.getegid ());
+		}
+
+		public static void SetIdentity (uint uid, uint gid)
+		{
+			// TODO: Use platform-specific code
+			if (IsUnix) {
+				Syscall.setgid (gid);
+				Syscall.setuid (uid);
+				LogIdentity ();
+			} else
+				Logger.Write (LogLevel.Warning, "Not dropping privileges");
+		}
+
+		public static void SetIdentity (string user, string group)
+		{
+			// TODO: Use platform-specific code
+			if (IsUnix) {
+				SetGroup (group);
+				SetUser (user);
+				LogIdentity ();
+			} else
+				Logger.Write (LogLevel.Warning, "Not dropping privileges");
+		}
+
+		public static IDisposable Impersonate(string user,string group)
+		{
+			uint uid = GetUid (user);
+			uint gid = GetGid (group);
+			uint euid = Syscall.geteuid ();
+			uint egid = Syscall.getegid ();
+			Syscall.setegid (gid);
+			Syscall.seteuid (uid);
+			return new IdentityToken (euid, egid);
+		}
+	}
+}
diff --git a/src/Mono.WebServer/RequestData.cs b/src/Mono.WebServer/RequestData.cs
new file mode 100644
index 0000000..5f01948
--- /dev/null
+++ b/src/Mono.WebServer/RequestData.cs
@@ -0,0 +1,61 @@
+//
+// Mono.WebServer.RequestData
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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.Text;
+
+namespace Mono.WebServer
+{
+	public class RequestData
+	{
+		public string Verb;
+		public string Path;
+		public string PathInfo;
+		public string QueryString;
+		public string Protocol;
+		public byte [] InputBuffer;
+
+		public RequestData (string verb, string path, string queryString, string protocol)
+		{
+			Verb = verb;
+			Path = path;
+			QueryString = queryString;
+			Protocol = protocol;
+		}
+
+		public override string ToString ()
+		{
+			var sb = new StringBuilder ();
+			sb.AppendFormat ("Verb: {0}\n", Verb);
+			sb.AppendFormat ("Path: {0}\n", Path);
+			sb.AppendFormat ("PathInfo: {0}\n", PathInfo);
+			sb.AppendFormat ("QueryString: {0}\n", QueryString);
+			return sb.ToString ();
+		}
+	}
+}
diff --git a/src/Mono.WebServer/RequestLineException.cs b/src/Mono.WebServer/RequestLineException.cs
new file mode 100644
index 0000000..a05fb45
--- /dev/null
+++ b/src/Mono.WebServer/RequestLineException.cs
@@ -0,0 +1,38 @@
+//
+// Mono.WebServer.RequestLineException
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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;
+
+namespace Mono.WebServer
+{
+	class RequestLineException : ApplicationException {
+		public RequestLineException () : base ("Error reading request line")
+		{
+		}
+	}
+}
diff --git a/src/Mono.WebServer/SearchPattern.cs b/src/Mono.WebServer/SearchPattern.cs
new file mode 100644
index 0000000..17d7601
--- /dev/null
+++ b/src/Mono.WebServer/SearchPattern.cs
@@ -0,0 +1,195 @@
+//
+// System.IO.SearchPattern.cs: Filename glob support.
+//
+// Author:
+//   Dan Lewis (dihlewis at yahoo.co.uk)
+//
+// (C) 2002
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.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.
+//
+
+namespace System.IO.Foo {
+
+	// FIXME: there's a complication with this algorithm under windows.
+	// the pattern '*.*' matches all files (i think . matches the extension),
+	// whereas under UNIX it should only match files containing the '.' character.
+
+	class SearchPattern
+	{
+		public SearchPattern (string pattern) : this (pattern, false) { }
+
+		public SearchPattern (string pattern, bool ignore)
+		{
+			SetPattern (pattern, ignore);
+		}
+
+		public void SetPattern (string pattern, bool ignore)
+		{
+			this.ignore = ignore;
+			Compile (pattern);
+		}
+		
+		public bool IsMatch (string text)
+		{
+			return Match (ops, text, 0);
+		}
+
+		// private
+
+		Op ops;		// the compiled pattern
+		bool ignore;	// ignore case
+
+		void Compile (string pattern)
+		{
+			if (pattern == null)
+				throw new ArgumentException ("Invalid search pattern.");
+
+			if (pattern == "*") {	// common case
+				ops = new Op (OpCode.True);
+				return;
+			}
+
+			ops = null;
+
+			int ptr = 0;
+			Op last_op = null;
+			while (ptr < pattern.Length) {
+				Op op;
+			
+				switch (pattern [ptr]) {
+				case '?':
+					op = new Op (OpCode.AnyChar);
+					++ ptr;
+					break;
+
+				case '*':
+					op = new Op (OpCode.AnyString);
+					++ ptr;
+					break;
+					
+				default:
+					op = new Op (OpCode.ExactString);
+					int end = pattern.IndexOfAny (WildcardChars, ptr);
+					if (end < 0)
+						end = pattern.Length;
+
+					op.Argument = pattern.Substring (ptr, end - ptr);
+					if (ignore)
+						op.Argument = op.Argument.ToLower ();
+
+					ptr = end;
+					break;
+				}
+
+				if (last_op == null)
+					ops = op;
+				else
+					last_op.Next = op;
+
+				last_op = op;
+			}
+
+			if (last_op == null)
+				ops = new Op (OpCode.End);
+			else
+				last_op.Next = new Op (OpCode.End);
+		}
+
+		bool Match (Op op, string text, int ptr)
+		{
+			while (op != null) {
+				switch (op.Code) {
+				case OpCode.True:
+					return true;
+
+				case OpCode.End:
+					if (ptr == text.Length)
+						return true;
+
+					return false;
+				
+				case OpCode.ExactString:
+					int length = op.Argument.Length;
+					if (ptr + length > text.Length)
+						return false;
+
+					string str = text.Substring (ptr, length);
+					if (ignore)
+						str = str.ToLower ();
+
+					if (str != op.Argument)
+						return false;
+
+					ptr += length;
+					break;
+
+				case OpCode.AnyChar:
+					if (++ ptr > text.Length)
+						return false;
+					break;
+
+				case OpCode.AnyString:
+					while (ptr <= text.Length) {
+						if (Match (op.Next, text, ptr))
+							return true;
+
+						++ ptr;
+					}
+
+					return false;
+				}
+
+				op = op.Next;
+			}
+
+			return true;
+		}
+
+		// private static
+
+		internal static readonly char [] WildcardChars = { '*', '?' };
+
+		class Op {
+			public Op (OpCode code)
+			{
+				Code = code;
+				Argument = null;
+				Next = null;
+			}
+		
+			public readonly OpCode Code;
+			public string Argument;
+			public Op Next;
+		}
+
+		enum OpCode {
+			ExactString,		// literal
+			AnyChar,		// ?
+			AnyString,		// *
+			End,			// end of pattern
+			True			// always succeeds
+		};
+	}
+}
diff --git a/src/Mono.WebServer/UnregisterRequestEventArgs.cs b/src/Mono.WebServer/UnregisterRequestEventArgs.cs
new file mode 100644
index 0000000..fb4ea1b
--- /dev/null
+++ b/src/Mono.WebServer/UnregisterRequestEventArgs.cs
@@ -0,0 +1,44 @@
+//
+// Mono.WebServer.UnregisterRequestEventArgs
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+// 	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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;
+
+namespace Mono.WebServer
+{
+	public class UnregisterRequestEventArgs : EventArgs
+	{
+		public int RequestId { get; private set; }
+
+		public UnregisterRequestEventArgs (int requestId)
+		{
+			RequestId = requestId;
+		}
+	}
+}
diff --git a/src/Mono.WebServer/UnregisterRequestEventHandler.cs b/src/Mono.WebServer/UnregisterRequestEventHandler.cs
new file mode 100644
index 0000000..d3961f7
--- /dev/null
+++ b/src/Mono.WebServer/UnregisterRequestEventHandler.cs
@@ -0,0 +1,33 @@
+//
+// Mono.WebServer.UnregisterRequestEventHandler
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+// 	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// (C) Copyright 2004-2010 Novell, Inc
+//
+// 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.
+//
+
+namespace Mono.WebServer
+{
+	public delegate void UnregisterRequestEventHandler (object sender, UnregisterRequestEventArgs args);
+}
diff --git a/src/Mono.WebServer/VPathToHost.cs b/src/Mono.WebServer/VPathToHost.cs
new file mode 100644
index 0000000..44b0fd1
--- /dev/null
+++ b/src/Mono.WebServer/VPathToHost.cs
@@ -0,0 +1,153 @@
+//
+// VPathToHost.cs
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+//	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// Copyright (c) Copyright 2002-2007 Novell, Inc
+//
+// 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.Web.Hosting;
+using System.Globalization;
+
+namespace Mono.WebServer
+{
+	public class VPathToHost
+	{
+		public readonly string vhost;
+		public readonly int vport;
+		public readonly string vpath;
+		public string realPath;
+		public readonly bool haveWildcard;
+		public IApplicationHost AppHost;
+		public IRequestBroker RequestBroker;
+
+		public VPathToHost (string vhost, int vport, string vpath, string realPath)
+		{
+			this.vhost = (vhost != null) ? vhost.ToLower (CultureInfo.InvariantCulture) : null;
+			this.vport = vport;
+			this.vpath = vpath;
+			if (String.IsNullOrEmpty (vpath) || vpath [0] != '/')
+				throw new ArgumentException ("Virtual path must begin with '/': " + vpath,
+							     "vpath");
+
+			this.realPath = realPath;
+			AppHost = null;
+			if (vhost != null && this.vhost.Length != 0 && this.vhost [0] == '*') {
+				haveWildcard = true;
+				if (this.vhost.Length > 2 && this.vhost [1] == '.')
+					this.vhost = this.vhost.Substring (2);
+			}
+		}
+
+		public bool TryClearHost (IApplicationHost host)
+		{
+			if (AppHost == host) {
+				AppHost = null;
+				return true;
+			}
+
+			return false;
+		}
+
+		public void UnloadHost ()
+		{
+			if (AppHost != null)
+				AppHost.Unload ();
+
+			AppHost = null;
+		}
+
+		public bool Redirect (string path, out string redirect)
+		{
+			redirect = null;
+			if (path.Length == vpath.Length - 1) {
+				redirect = vpath;
+				return true;
+			}
+
+			return false;
+		}
+
+		public bool Match (string vhost, int vport, string vpath)
+		{
+			if (vport != -1 && this.vport != -1 && vport != this.vport)
+				return false;
+
+			if (vpath == null)
+				return false;
+
+			if (vhost != null && this.vhost != null && this.vhost != "*") {
+				int length = this.vhost.Length;
+				string lwrvhost = vhost.ToLower (CultureInfo.InvariantCulture);
+				if (haveWildcard) {
+					if (length > vhost.Length)
+						return false;
+
+					if (length == vhost.Length && this.vhost != lwrvhost)
+						return false;
+
+					if (vhost [vhost.Length - length - 1] != '.')
+						return false;
+
+					if (!lwrvhost.EndsWith (this.vhost))
+						return false;
+
+				} else if (this.vhost != lwrvhost) {
+					return false;
+				}
+			}
+
+			int local = vpath.Length;
+			int vlength = this.vpath.Length;
+			if (vlength > local) {
+				// Check for /xxx requests to be redirected to /xxx/
+				if (this.vpath [vlength - 1] != '/')
+					return false;
+
+				return (vlength - 1 == local && this.vpath.Substring (0, vlength - 1) == vpath);
+			}
+
+			return (vpath.StartsWith (this.vpath));
+		}
+
+		public void CreateHost (ApplicationServer server, WebSource webSource)
+		{
+			string v = vpath;
+			if (v != "/" && v.EndsWith ("/")) {
+				v = v.Substring (0, v.Length - 1);
+			}
+
+			AppHost = ApplicationHost.CreateApplicationHost (webSource.GetApplicationHostType(), v, realPath) as IApplicationHost;
+			AppHost.Server = server;
+			
+			if (!server.SingleApplication) {
+				// Link the host in the application domain with a request broker in the main domain
+				RequestBroker = webSource.CreateRequestBroker ();
+				AppHost.RequestBroker = RequestBroker;
+			}
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Version.cs b/src/Mono.WebServer/Version.cs
new file mode 100644
index 0000000..ba27e53
--- /dev/null
+++ b/src/Mono.WebServer/Version.cs
@@ -0,0 +1,62 @@
+//
+// Version.cs
+//
+// Author:
+//   Leonardo Taglialegne <leonardo.taglialegne at gmail.com>
+//
+// Copyright (c) 2013 Leonardo Taglialegne.
+//
+// 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.IO;
+using System.Reflection;
+
+namespace Mono.WebServer {
+	public static class Version
+	{
+		public static void Show ()
+		{
+			Assembly assembly = Assembly.GetExecutingAssembly ();
+			string version = assembly.GetName ().Version.ToString ();
+
+			// string title = GetAttribute<AssemblyTitleAttribute> (a => a.Title);
+			string copyright = GetAttribute<AssemblyCopyrightAttribute> (a => a.Copyright);
+			string description = GetAttribute<AssemblyDescriptionAttribute> (a => a.Description);
+
+			Console.WriteLine ("{0} {1}\n(c) {2}\n{3}",
+				Path.GetFileName (assembly.Location), version,
+				copyright, description);
+		}
+
+		static string GetAttribute<T> (Func<T, string> func) where T : class
+		{
+			Assembly assembly = Assembly.GetExecutingAssembly ();
+			var attributes = assembly.GetCustomAttributes (typeof (T), false);
+			if (attributes.Length == 0)
+				return String.Empty;
+			var att = attributes [0] as T;
+			if (att == null)
+				return String.Empty;
+			return func (att);
+		}
+	}
+}
diff --git a/src/Mono.WebServer/WebSource.cs b/src/Mono.WebServer/WebSource.cs
new file mode 100644
index 0000000..ef7698c
--- /dev/null
+++ b/src/Mono.WebServer/WebSource.cs
@@ -0,0 +1,55 @@
+//
+// Mono.WebServer.WebSource
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+// 	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// Documentation:
+//	Brian Nickel
+//
+// (C) Copyright 2004-2010 Novell, Inc. (http://www.novell.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.Sockets;
+
+namespace Mono.WebServer
+{
+	public abstract class WebSource : IDisposable
+	{
+		public abstract Socket CreateSocket ();
+		public abstract Worker CreateWorker (Socket client, ApplicationServer server);
+		public abstract Type GetApplicationHostType ();
+		public abstract IRequestBroker CreateRequestBroker ();
+
+		public void Dispose ()
+		{
+			Dispose (true);
+			GC.SuppressFinalize (this);
+		}
+
+		protected virtual void Dispose (bool disposing)
+		{
+		}
+	}	
+}
diff --git a/src/Mono.WebServer/WebTrace.cs b/src/Mono.WebServer/WebTrace.cs
new file mode 100644
index 0000000..5303431
--- /dev/null
+++ b/src/Mono.WebServer/WebTrace.cs
@@ -0,0 +1,137 @@
+//
+// ApplicationServer.cs
+//
+// Authors:
+//      Marek Habersack (mhabersack at novell.com)
+//
+// Copyright (c) Copyright 2007 Novell, Inc
+//
+// 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.Text;
+using System.Threading;
+using System.Diagnostics;
+using System.Reflection;
+
+namespace Mono.WebServer
+{
+	public sealed class WebTrace
+	{
+		static string GetMethodName (StackFrame sf)
+		{
+			MethodBase mi = sf.GetMethod ();
+
+			return mi != null ? String.Format ("{0}.{1}(): ", mi.ReflectedType, mi.Name) : null;
+		}
+
+		static string GetExtraInfo (StackFrame sf = null)
+		{
+			string threadid = String.Format ("thread_id: {0}", Thread.CurrentThread.ManagedThreadId.ToString ("x"));
+			string domainid = String.Format ("appdomain_id: {0}", AppDomain.CurrentDomain.Id.ToString ("x"));			
+			string filepath = sf == null ? null : sf.GetFileName ();
+			int lineNumber = sf == null ? -1 : sf.GetFileLineNumber ();
+			string format = String.IsNullOrEmpty (filepath) ? " [{0}, {1}]" : " [{0}, {1}, in {2}:{3}]";
+			return String.Format (format, domainid, threadid, filepath, lineNumber);
+		}
+
+		static void Enter (string format, StackFrame sf, params object[] parms)
+		{
+			var sb = new StringBuilder ("Enter: ");
+					
+			string methodName = GetMethodName (sf);
+			if (methodName != null)
+				sb.Append (methodName);
+			if (format != null)
+				sb.AppendFormat (format, parms);
+			sb.Append (GetExtraInfo (sf));
+			
+			Trace.WriteLine (sb.ToString ());
+			Trace.Indent ();
+		}
+		
+		[Conditional ("WEBTRACE")]
+		public static void Enter (string format, params object[] parms)
+		{
+			Enter (format, new StackFrame (1), parms);
+		}
+
+		[Conditional ("WEBTRACE")]
+		public static void Enter ()
+		{
+			Enter (null, new StackFrame (1), null);
+		}
+
+		static void Leave (string format, StackFrame sf, params object[] parms)
+		{
+			var sb = new StringBuilder ("Leave: ");
+
+			string methodName = GetMethodName (sf);
+			if (methodName != null)
+				sb.Append (methodName);
+			if (format != null)
+				sb.AppendFormat (format, parms);
+			sb.Append (GetExtraInfo (sf));
+			
+			Trace.Unindent ();
+			Trace.WriteLine (sb.ToString ());
+		}
+		
+		[Conditional ("WEBTRACE")]
+		public static void Leave (string format, params object[] parms)
+		{
+			Leave (format, new StackFrame (1), parms);
+		}
+
+		[Conditional ("WEBTRACE")]
+		public static void Leave ()
+		{
+			Leave (null, new StackFrame (1), null);
+		}
+
+		[Conditional ("WEBTRACE")]
+		public static void WriteLine (string format, params object[] parms)
+		{
+			if (format == null)
+				return;
+			
+			var sb = new StringBuilder ();
+			sb.AppendFormat (format, parms);
+			sb.Append (GetExtraInfo ());
+			Trace.WriteLine (sb.ToString ());
+		}
+
+		[Conditional ("WEBTRACE")]
+		public static void WriteLineIf (bool cond, string format, params object[] parms)
+		{
+			if (!cond)
+				return;
+			
+			if (format == null)
+				return;
+			
+			var sb = new StringBuilder ();
+			sb.AppendFormat (format, parms);
+			sb.Append (GetExtraInfo ());
+			Trace.WriteLine (sb.ToString ());
+		}
+	}
+}
diff --git a/src/Mono.WebServer/Worker.cs b/src/Mono.WebServer/Worker.cs
new file mode 100644
index 0000000..3487dc8
--- /dev/null
+++ b/src/Mono.WebServer/Worker.cs
@@ -0,0 +1,62 @@
+//
+// Mono.WebServer.Worker
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo at ximian.com)
+// 	Lluis Sanchez Gual (lluis at ximian.com)
+//
+// Documentation:
+//	Brian Nickel
+//
+// (C) Copyright 2004-2010 Novell, Inc. (http://www.novell.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.
+//
+
+namespace Mono.WebServer
+{
+	public abstract class Worker
+	{
+		public virtual bool IsAsync {
+			get { return false; }
+		}
+
+		public virtual void SetReuseCount (int reuses)
+		{
+		}
+
+		public virtual int GetRemainingReuses ()
+		{
+			return 0;
+		}
+
+		public abstract void Run (object state);
+
+		public abstract int Read (byte [] buffer, int position, int size);
+
+		public abstract void Write (byte [] buffer, int position, int size);
+		
+		public abstract void Close ();
+		
+		public abstract void Flush ();
+
+		public abstract bool IsConnected ();
+	}
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mono/packages/xsp.git



More information about the Pkg-mono-svn-commits mailing list