做此程序的原因是将软件部署简化,省去IIS的麻烦部署,减少项目实施人员的工作量和工作复杂度
Server sv = new Server(8000, "/", @"D:\web", IPAddress.Any, null, "Login.aspx");
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) 2010 Sky Sanders. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.Remoting; using System.Security.Permissions; using System.Security.Principal; using System.Text; using System.Threading; using System.Web; using System.Web.Hosting; #endregion namespace SimpleWebServer { ///<summary> ///</summary> [PermissionSet(SecurityAction.LinkDemand, Name = "Everything"), PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] public class Server : MarshalByRefObject, IDisposable { ///<summary> ///</summary> public List<string> Plugins = new List<string>(); ///<summary> ///</summary> public readonly ApplicationManager ApplicationManager; private readonly bool _disableDirectoryListing; private readonly string _hostName; private readonly IPAddress _ipAddress; private readonly object _lockObject; private readonly string _physicalPath; private readonly int _port; private readonly bool _requireAuthentication; //private readonly int _timeoutInterval; private readonly string _virtualPath; private bool _disposed; private Host _host; private IntPtr _processToken; private string _processUser; //private int _requestCount; private bool _shutdownInProgress; private Socket _socket; //private Timer _timer; private string _appId; private string _dfPage; ///<summary> ///</summary> public string AppId { get { return _appId; } } ///<summary> ///</summary> public AppDomain HostAppDomain { get { if (_host == null) { GetHost(); } if (_host != null) { return _host.AppDomain; } return null; } } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> public Server(int port, string virtualPath, string physicalPath) : this(port, virtualPath, physicalPath, false, false) { } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="physicalPath"></param> public Server(int port, string physicalPath) : this(port, "/", physicalPath, IPAddress.Loopback) { } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> ///<param name="ipAddress"></param> ///<param name="hostName"></param> ///<param name="requireAuthentication"></param> public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress, string hostName) : this(port, virtualPath, physicalPath, ipAddress, hostName,false, false, null) { } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> ///<param name="requireAuthentication"></param> public Server(int port, string virtualPath, string physicalPath, bool requireAuthentication) : this(port, virtualPath, physicalPath, requireAuthentication, false) { } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> ///<param name="ipAddress"></param> ///<param name="hostName"></param> public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress, string hostName,string dfPage) : this(port, virtualPath, physicalPath, ipAddress, hostName, false, false, dfPage) { } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> ///<param name="ipAddress"></param> ///<param name="hostName"></param> ///<param name="requireAuthentication"></param> ///<param name="disableDirectoryListing"></param> public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress, string hostName, bool requireAuthentication, bool disableDirectoryListing, string dfPage) : this(port, virtualPath, physicalPath, requireAuthentication, disableDirectoryListing) { _ipAddress = ipAddress; _hostName = hostName; if (!String.IsNullOrEmpty(dfPage)) dfPage.TrimStart('/'); _dfPage = "/" + dfPage; //_timeoutInterval = timeout; } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> ///<param name="ipAddress"></param> public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress) : this(port, virtualPath, physicalPath, ipAddress, null, false, false , null) { } ///<summary> ///</summary> ///<param name="port"></param> ///<param name="virtualPath"></param> ///<param name="physicalPath"></param> ///<param name="requireAuthentication"></param> ///<param name="disableDirectoryListing"></param> public Server(int port, string virtualPath, string physicalPath, bool requireAuthentication, bool disableDirectoryListing) { try { Assembly.ReflectionOnlyLoad("Common.Logging"); } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { } _ipAddress = IPAddress.Loopback; _requireAuthentication = requireAuthentication; _disableDirectoryListing = disableDirectoryListing; _lockObject = new object(); _port = port; _virtualPath = virtualPath; _physicalPath = Path.GetFullPath(physicalPath); _physicalPath = _physicalPath.EndsWith("\\", StringComparison.Ordinal) ? _physicalPath : _physicalPath + "\\"; ApplicationManager = ApplicationManager.GetApplicationManager(); string uniqueAppString = string.Concat(virtualPath, physicalPath,":",_port.ToString()).ToLowerInvariant(); _appId = (uniqueAppString.GetHashCode()).ToString("x", CultureInfo.InvariantCulture); ObtainProcessToken(); } ///<summary> ///</summary> public bool DisableDirectoryListing { get { return _disableDirectoryListing; } } ///<summary> ///</summary> public bool RequireAuthentication { get { return _requireAuthentication; } } /////<summary> /////</summary> //public int TimeoutInterval //{ // get { return _timeoutInterval; } //} ///<summary> ///</summary> public string HostName { get { return _hostName; } } ///<summary> ///</summary> // ReSharper disable InconsistentNaming public IPAddress IPAddress // ReSharper restore InconsistentNaming { get { return _ipAddress; } } ///<summary> ///</summary> public string PhysicalPath { get { return _physicalPath; } } ///<summary> ///</summary> public int Port { get { return _port; } } ///<summary> ///</summary> public string RootUrl { get { string hostname = _hostName; if (string.IsNullOrEmpty(_hostName)) { if (_ipAddress.Equals(IPAddress.Loopback) || _ipAddress.Equals(IPAddress.IPv6Loopback) || _ipAddress.Equals(IPAddress.Any) || _ipAddress.Equals(IPAddress.IPv6Any)) { hostname = "localhost"; } else { hostname = _ipAddress.ToString(); } } return _port != 80 ? String.Format("http://{0}:{1}{2}", hostname, _port, _virtualPath) : //FIX: #12017 - TODO:TEST string.Format("http://{0}{1}", hostname, _virtualPath); } } ///<summary> ///</summary> public string VirtualPath { get { return _virtualPath; } } #region IDisposable Members /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> /// <filterpriority>2</filterpriority> public void Dispose() { if (!_disposed) { ShutDown(); } _disposed = true; GC.SuppressFinalize(this); } #endregion ///<summary> ///</summary> public event EventHandler<RequestEventArgs> RequestComplete; /////<summary> /////</summary> //public event EventHandler TimedOut; ///<summary> ///</summary> ///<returns></returns> public IntPtr GetProcessToken() { return _processToken; } ///<summary> ///</summary> ///<returns></returns> public string GetProcessUser() { return _processUser; } ///<summary> ///</summary> public void HostStopped() { _host = null; } /// <summary> /// Obtains a lifetime service object to control the lifetime policy for this instance. /// </summary> /// <returns> /// An object of type <see cref="T:System.Runtime.Remoting.Lifetime.ILease"/> used to control the lifetime policy for this instance. This is the current lifetime service object for this instance if one exists; otherwise, a new lifetime service object initialized to the value of the <see cref="P:System.Runtime.Remoting.Lifetime.LifetimeServices.LeaseManagerPollTime"/> property. /// </returns> /// <exception cref="T:System.Security.SecurityException">The immediate caller does not have infrastructure permission. /// </exception><filterpriority>2</filterpriority><PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="RemotingConfiguration, Infrastructure"/></PermissionSet> [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)] public override object InitializeLifetimeService() { // never expire the license return null; } // called at the end of request processing // to disconnect the remoting proxy for Connection object // and allow GC to pick it up /// <summary> /// </summary> /// <param name="conn"></param> /// <param name="userName"></param> public void OnRequestEnd(Connection conn) { try { OnRequestComplete(conn.Id); } catch { // swallow - we don't want consumer killing the server } RemotingServices.Disconnect(conn); //DecrementRequestCount(); } ///<summary> ///</summary> public void Start() { _socket = CreateSocketBindAndListen(AddressFamily.InterNetwork, _ipAddress, _port); //start the timer //DecrementRequestCount(); ThreadPool.QueueUserWorkItem(delegate { while (!_shutdownInProgress) { try { Socket acceptedSocket = _socket.Accept(); ThreadPool.QueueUserWorkItem(delegate { if (!_shutdownInProgress) { Connection conn = new Connection(this, acceptedSocket); if (conn.WaitForRequestBytes() == 0) { conn.WriteErrorAndClose(400); return; } Host host = GetHost(); if (host == null) { conn.WriteErrorAndClose(500); return; } //IncrementRequestCount(); host.ProcessRequest(conn,_dfPage); } }); } catch { Thread.Sleep(100); } } }); } /// <summary> /// Allows an <see cref="T:System.Object"/> to attempt to free resources and perform other cleanup operations before the <see cref="T:System.Object"/> is reclaimed by garbage collection. /// </summary> ~Server() { Dispose(); } private static Socket CreateSocketBindAndListen(AddressFamily family, IPAddress address, int port) { Socket socket = new Socket(family, SocketType.Stream, ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); socket.Bind(new IPEndPoint(address, port)); socket.Listen((int)SocketOptionName.MaxConnections); return socket; } /// <summary> /// /// </summary> /// <param name="virtualPath"></param> /// <param name="physicalPath"></param> /// <param name="hostType"></param> /// <param name="port"></param> /// <returns></returns> /// <remarks> /// This is Dmitry's hack to enable running outside of GAC. /// There are some errors being thrown when running in proc /// </remarks> private object CreateWorkerAppDomainWithHost(string virtualPath, string physicalPath, Type hostType,int port) { // create BuildManagerHost in the worker app domain //ApplicationManager appManager = ApplicationManager.GetApplicationManager(); Type buildManagerHostType = typeof(HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost"); IRegisteredObject buildManagerHost = ApplicationManager.CreateObject(_appId, buildManagerHostType, virtualPath, physicalPath, false); // call BuildManagerHost.RegisterAssembly to make Host type loadable in the worker app domain buildManagerHostType.InvokeMember("RegisterAssembly", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, buildManagerHost, new object[] { hostType.Assembly.FullName, hostType.Assembly.Location }); // create Host in the worker app domain // FIXME: getting FileLoadException Could not load file or assembly 'WebDev.WebServer20, Version=4.0.1.6, Culture=neutral, PublicKeyToken=f7f6e0b4240c7c27' or one of its dependencies. Failed to grant permission to execute. (Exception from HRESULT: 0x80131418) // when running dnoa 3.4 samples - webdev is registering trust somewhere that we are not return ApplicationManager.CreateObject(_appId, hostType, virtualPath, physicalPath, false); } //private void DecrementRequestCount() //{ // lock (_lockObject) // { // _requestCount--; // if (_requestCount < 1) // { // _requestCount = 0; // if (_timeoutInterval > 0 && _timer == null) // { // _timer = new Timer(TimeOut, null, _timeoutInterval, Timeout.Infinite); // } // } // } //} private Host GetHost() { if (_shutdownInProgress) return null; Host host = _host; if (host == null) { #if NET40 object obj2 = new object(); bool flag = false; try { Monitor.Enter(obj2 = _lockObject, ref flag); host = _host; if (host == null) { host = (Host)CreateWorkerAppDomainWithHost(_virtualPath, _physicalPath, typeof(Host),Port); host.Configure(this, _port, _virtualPath, _physicalPath, _requireAuthentication, _disableDirectoryListing); _host = host; } } finally { if (flag) { Monitor.Exit(obj2); } } #else lock (_lockObject) { host = _host; if (host == null) { host = (Host)CreateWorkerAppDomainWithHost(_virtualPath, _physicalPath, typeof(Host),Port); host.Configure(this, _port, _virtualPath, _physicalPath, _requireAuthentication, _disableDirectoryListing); _host = host; } } #endif } return host; } //private void IncrementRequestCount() //{ // lock (_lockObject) // { // _requestCount++; // if (_timer != null) // { // _timer.Dispose(); // _timer = null; // } // } //} private void ObtainProcessToken() { if (Interop.ImpersonateSelf(2)) { Interop.OpenThreadToken(Interop.GetCurrentThread(), 0xf01ff, true, ref _processToken); Interop.RevertToSelf(); // ReSharper disable PossibleNullReferenceException _processUser = WindowsIdentity.GetCurrent().Name; // ReSharper restore PossibleNullReferenceException } } private void OnRequestComplete(Guid id) { EventHandler<RequestEventArgs> complete = RequestComplete; if (complete != null) { complete(this, new RequestEventArgs(id)); } } ///<summary> ///</summary> public void ShutDown() { if (_shutdownInProgress) { return; } _shutdownInProgress = true; try { if (_socket != null) { _socket.Close(); } } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { // TODO: why the swallow? } finally { _socket = null; } try { if (_host != null) { _host.Shutdown(); } // the host is going to raise an event that this class uses to null the field. // just wait until the field is nulled and continue. while (_host != null) { new AutoResetEvent(false).WaitOne(100); } } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { // TODO: what am i afraid of here? } } //private void TimeOut(object ignored) //{ // TimeOut(); //} /////<summary> /////</summary> //public void TimeOut() //{ // ShutDown(); // OnTimeOut(); //} //private void OnTimeOut() //{ // EventHandler handler = TimedOut; // if (handler != null) handler(this, EventArgs.Empty); //} } }
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) 2010 Sky Sanders. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Web.UI; #endregion namespace SimpleWebServer { internal static class CommonExtensions { public static string ConvertToHexView(this byte[] value, int numBytesPerRow) { if (value == null) return null; List<string> hexSplit = BitConverter.ToString(value) .Replace('-', ' ') .Trim() .SplitIntoChunks(numBytesPerRow*3) .ToList(); int byteAddress = 0; StringBuilder sb = new StringBuilder(); for (int i = 0; i < hexSplit.Count; i++) { sb.AppendLine(byteAddress.ToString("X4") + ":\t" + hexSplit[i]); byteAddress += numBytesPerRow; } return sb.ToString(); } /// <summary> /// CassiniDev FIX: #12506 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public static string GetContentType(string fileName) { if (!File.Exists(fileName)) { return null; } string contentType; FileInfo info = new FileInfo(fileName); string extension = info.Extension.ToLowerInvariant(); #region switch filetype switch (extension) { //NOTE: these are fallbacks - and should be refined as needed // Only if the request does not already know // the content-type will this switch be hit - meaning that // served content-types for extensions listed here may not match // as this method may not be polled. case ".svgz": contentType = "image/svg+xml"; break; // from registry - last resort - verified mappings follow case ".3g2": contentType = "video/3gpp2"; break; case ".3gp": contentType = "video/3gpp"; break; case ".3gp2": contentType = "video/3gpp2"; break; case ".3gpp": contentType = "video/3gpp"; break; case ".adt": contentType = "audio/vnd.dlna.adts"; break; case ".amr": contentType = "audio/AMR"; break; case ".addin": contentType = "text/xml"; break; case ".evr": contentType = "audio/evrc-qcp"; break; case ".evrc": contentType = "audio/evrc-qcp"; break; case ".ssisdeploymentmanifest": contentType = "text/xml"; break; case ".xoml": contentType = "text/plain"; break; case ".aac": contentType = "audio/aac"; break; case ".ac3": contentType = "audio/ac3"; break; case ".accda": contentType = "application/msaccess"; break; case ".accdb": contentType = "application/msaccess"; break; case ".accdc": contentType = "application/msaccess"; break; case ".accde": contentType = "application/msaccess"; break; case ".accdr": contentType = "application/msaccess"; break; case ".accdt": contentType = "application/msaccess"; break; case ".acrobatsecuritysettings": contentType = "application/vnd.adobe.acrobat-security-settings"; break; case ".ad": contentType = "text/plain"; break; case ".ade": contentType = "application/msaccess"; break; case ".adobebridge": contentType = "application/x-bridge-url"; break; case ".adp": contentType = "application/msaccess"; break; case ".adts": contentType = "audio/vnd.dlna.adts"; break; case ".amc": contentType = "application/x-mpeg"; break; case ".application": contentType = "application/x-ms-application"; break; case ".asa": contentType = "application/xml"; break; case ".asax": contentType = "application/xml"; break; case ".ascx": contentType = "application/xml"; break; case ".ashx": contentType = "application/xml"; break; case ".asm": contentType = "text/plain"; break; case ".asmx": contentType = "application/xml"; break; case ".aspx": contentType = "application/xml"; break; case ".awf": contentType = "application/vnd.adobe.workflow"; break; case ".biz": contentType = "text/xml"; break; case ".c2r": contentType = "text/vnd-ms.click2record+xml"; break; case ".caf": contentType = "audio/x-caf"; break; case ".cc": contentType = "text/plain"; break; case ".cd": contentType = "text/plain"; break; case ".cdda": contentType = "audio/aiff"; break; case ".config": contentType = "application/xml"; break; case ".contact": contentType = "text/x-ms-contact"; break; case ".coverage": contentType = "application/xml"; break; case ".cpp": contentType = "text/plain"; break; case ".cs": contentType = "text/plain"; break; case ".csdproj": contentType = "text/plain"; break; case ".csproj": contentType = "text/plain"; break; case ".jar": contentType = "application/java-archive"; break; case ".csv": contentType = "application/vnd.ms-excel"; break; case ".cur": contentType = "text/plain"; break; case ".cxx": contentType = "text/plain"; break; case ".datasource": contentType = "application/xml"; break; case ".dbproj": contentType = "text/plain"; break; case ".dcd": contentType = "text/xml"; break; case ".dd": contentType = "text/plain"; break; case ".def": contentType = "text/plain"; break; case ".design": contentType = "image/design"; break; case ".dgml": contentType = "application/xml"; break; case ".dib": contentType = "image/bmp"; break; case ".dif": contentType = "video/x-dv"; break; case ".docm": contentType = "application/vnd.ms-word.document.macroEnabled.12"; break; case ".docx": contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; break; case ".dotm": contentType = "application/vnd.ms-word.template.macroEnabled.12"; break; case ".dotx": contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template"; break; case ".dsp": contentType = "text/plain"; break; case ".dsprototype": contentType = "text/plain"; break; case ".dsw": contentType = "text/plain"; break; case ".dtd": contentType = "application/xml-dtd"; break; case ".dtsconfig": contentType = "text/xml"; break; case ".dv": contentType = "video/x-dv"; break; case ".dwfx": contentType = "model/vnd.dwfx+xps"; break; case ".easmx": contentType = "model/vnd.easmx+xps"; break; case ".edrwx": contentType = "model/vnd.edrwx+xps"; break; case ".eprtx": contentType = "model/vnd.eprtx+xps"; break; case ".fdf": contentType = "application/vnd.fdf"; break; case ".filters": contentType = "Application/xml"; break; case ".flc": contentType = "video/flc"; break; case ".fo": contentType = "text/xml"; break; case ".fsscript": contentType = "application/fsharp-script"; break; case ".fsx": contentType = "application/fsharp-script"; break; case ".generictest": contentType = "application/xml"; break; case ".group": contentType = "text/x-ms-group"; break; case ".gsm": contentType = "audio/x-gsm"; break; case ".hpp": contentType = "text/plain"; break; case ".hxa": contentType = "application/xml"; break; case ".hxc": contentType = "application/xml"; break; case ".hxd": contentType = "application/octet-stream"; break; case ".hxe": contentType = "application/xml"; break; case ".hxf": contentType = "application/xml"; break; case ".hxh": contentType = "application/octet-stream"; break; case ".hxi": contentType = "application/octet-stream"; break; case ".hxk": contentType = "application/xml"; break; case ".hxq": contentType = "application/octet-stream"; break; case ".hxr": contentType = "application/octet-stream"; break; case ".hxs": contentType = "application/octet-stream"; break; case ".hxt": contentType = "application/xml"; break; case ".hxv": contentType = "application/xml"; break; case ".hxw": contentType = "application/octet-stream"; break; case ".hxx": contentType = "text/plain"; break; case ".i": contentType = "text/plain"; break; case ".idl": contentType = "text/plain"; break; case ".inc": contentType = "text/plain"; break; case ".inl": contentType = "text/plain"; break; case ".ipproj": contentType = "text/plain"; break; case ".iqy": contentType = "text/x-ms-iqy"; break; case ".ismv": contentType = "video/ismv"; break; case ".jsx": contentType = "text/plain"; break; case ".jsxbin": contentType = "text/plain"; break; case ".jtx": contentType = "application/x-jtx+xps"; break; case ".ldd": contentType = "text/plain"; break; case ".library-ms": contentType = "application/windows-library+xml"; break; case ".loadtest": contentType = "application/xml"; break; case ".lsaprototype": contentType = "text/plain"; break; case ".lst": contentType = "text/plain"; break; case ".m1v": contentType = "video/mpeg"; break; case ".m2t": contentType = "video/vnd.dlna.mpeg-tts"; break; case ".m2ts": contentType = "video/vnd.dlna.mpeg-tts"; break; case ".m2v": contentType = "video/mpeg"; break; case ".m4a": contentType = "audio/mp4"; break; case ".m4b": contentType = "audio/x-m4b"; break; case ".m4p": contentType = "audio/x-m4p"; break; case ".m4v": contentType = "video/x-m4v"; break; case ".mac": contentType = "image/x-macpaint"; break; case ".mak": contentType = "text/plain"; break; case ".map": contentType = "text/plain"; break; case ".master": contentType = "application/xml"; break; case ".mda": contentType = "application/msaccess"; break; case ".mde": contentType = "application/msaccess"; break; case ".mdp": contentType = "text/plain"; break; case ".mfp": contentType = "application/x-shockwave-flash"; break; case ".mk": contentType = "text/plain"; break; case ".mod": contentType = "video/mpeg"; break; case ".mp2v": contentType = "video/mpeg"; break; case ".mp4": contentType = "video/mp4"; break; case ".mp4v": contentType = "video/mp4"; break; case ".mpf": contentType = "application/vnd.ms-mediapackage"; break; case ".mqv": contentType = "video/quicktime"; break; case ".mts": contentType = "video/vnd.dlna.mpeg-tts"; break; case ".mtx": contentType = "application/xml"; break; case ".mxp": contentType = "application/x-mmxp"; break; case ".nix": contentType = "application/x-mix-transfer"; break; case ".odc": contentType = "text/x-ms-odc"; break; case ".odh": contentType = "text/plain"; break; case ".odl": contentType = "text/plain"; break; case ".odp": contentType = "application/vnd.oasis.opendocument.presentation"; break; case ".ods": contentType = "application/vnd.oasis.opendocument.spreadsheet"; break; case ".odt": contentType = "application/vnd.oasis.opendocument.text"; break; case ".orderedtest": contentType = "application/xml"; break; case ".osdx": contentType = "application/opensearchdescription+xml"; break; case ".pct": contentType = "image/pict"; break; case ".pcx": contentType = "image/x-pcx"; break; case ".pdfxml": contentType = "application/vnd.adobe.pdfxml"; break; case ".pdx": contentType = "application/vnd.adobe.pdx"; break; case ".pic": contentType = "image/pict"; break; case ".pict": contentType = "image/pict"; break; case ".pkgdef": contentType = "text/plain"; break; case ".pkgundef": contentType = "text/plain"; break; case ".png": contentType = "image/png"; break; case ".pnt": contentType = "image/x-macpaint"; break; case ".pntg": contentType = "image/x-macpaint"; break; case ".potm": contentType = "application/vnd.ms-powerpoint.template.macroEnabled.12"; break; case ".potx": contentType = "application/vnd.openxmlformats-officedocument.presentationml.template"; break; case ".ppa": contentType = "application/vnd.ms-powerpoint"; break; case ".ppam": contentType = "application/vnd.ms-powerpoint.addin.macroEnabled.12"; break; case ".ppsm": contentType = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"; break; case ".ppsx": contentType = "application/vnd.openxmlformats-officedocument.presentationml.slideshow"; break; case ".pptm": contentType = "application/vnd.ms-powerpoint.presentation.macroEnabled.12"; break; case ".pptx": contentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; break; case ".psc1": contentType = "application/PowerShell"; break; case ".psess": contentType = "application/xml"; break; case ".pwz": contentType = "application/vnd.ms-powerpoint"; break; case ".pxr": contentType = "image/pxr"; break; case ".qcp": contentType = "audio/vnd.qcelp"; break; case ".qht": contentType = "text/x-html-insertion"; break; case ".qhtm": contentType = "text/x-html-insertion"; break; case ".qti": contentType = "image/x-quicktime"; break; case ".qtif": contentType = "image/x-quicktime"; break; case ".qtl": contentType = "application/x-quicktimeplayer"; break; case ".rat": contentType = "application/rat-file"; break; case ".raw": contentType = "application/octet-stream"; break; case ".rc": contentType = "text/plain"; break; case ".rc2": contentType = "text/plain"; break; case ".rct": contentType = "text/plain"; break; case ".rdf": contentType = "text/xml"; break; case ".rdlc": contentType = "application/xml"; break; case ".rels": contentType = "application/vnd.ms-package.relationships+xml"; break; case ".resx": contentType = "application/xml"; break; case ".rgs": contentType = "text/plain"; break; case ".rjt": contentType = "application/vnd.rn-realsystem-rjt"; break; case ".rm": contentType = "application/vnd.rn-realmedia"; break; case ".rmf": contentType = "application/vnd.adobe.rmf"; break; case ".rmj": contentType = "application/vnd.rn-realsystem-rmj"; break; case ".rmm": contentType = "audio/x-pn-realaudio"; break; case ".rmp": contentType = "application/vnd.rn-rn_music_package"; break; case ".rms": contentType = "application/vnd.rn-realaudio-secure"; break; case ".rmvb": contentType = "application/vnd.rn-realmedia-vbr"; break; case ".rmx": contentType = "application/vnd.rn-realsystem-rmx"; break; case ".rnx": contentType = "application/vnd.rn-realplayer"; break; case ".rp": contentType = "image/vnd.rn-realpix"; break; case ".rpm": contentType = "audio/x-pn-realaudio-plugin"; break; case ".rqy": contentType = "text/x-ms-rqy"; break; case ".rsml": contentType = "application/vnd.rn-rsml"; break; case ".rt": contentType = "text/vnd.rn-realtext"; break; case ".rtsp": contentType = "application/x-rtsp"; break; case ".ruleset": contentType = "application/xml"; break; case ".rv": contentType = "video/vnd.rn-realvideo"; break; case ".s": contentType = "text/plain"; break; case ".sd": contentType = "text/plain"; break; case ".sd2": contentType = "audio/x-sd2"; break; case ".sdm": contentType = "text/plain"; break; case ".sdmdocument": contentType = "text/plain"; break; case ".sdp": contentType = "application/sdp"; break; case ".sdv": contentType = "video/sd-video"; break; case ".searchConnector-ms": contentType = "application/windows-search-connector+xml"; break; case ".settings": contentType = "application/xml"; break; case ".sgi": contentType = "image/x-sgi"; break; case ".shtml": contentType = "text/html"; break; case ".sitemap": contentType = "application/xml"; break; case ".skin": contentType = "application/xml"; break; case ".sldm": contentType = "application/vnd.ms-powerpoint.slide.macroEnabled.12"; break; case ".sldx": contentType = "application/vnd.openxmlformats-officedocument.presentationml.slide"; break; case ".slk": contentType = "application/vnd.ms-excel"; break; case ".sln": contentType = "text/plain"; break; case ".slupkg-ms": contentType = "application/x-ms-license"; break; case ".smi": contentType = "application/smil"; break; case ".smil": contentType = "application/smil"; break; case ".snippet": contentType = "application/xml"; break; case ".sol": contentType = "text/plain"; break; case ".sor": contentType = "text/plain"; break; case ".srf": contentType = "text/plain"; break; case ".svc": contentType = "application/xml"; break; case ".tga": contentType = "image/x-targa"; break; case ".targa": contentType = "image/x-targa"; break; case ".testrunconfig": contentType = "application/xml"; break; case ".testsettings": contentType = "application/xml"; break; case ".thmx": contentType = "application/vnd.ms-officetheme"; break; case ".tlh": contentType = "text/plain"; break; case ".tli": contentType = "text/plain"; break; case ".trx": contentType = "application/xml"; break; case ".ts": contentType = "video/vnd.dlna.mpeg-tts"; break; case ".tts": contentType = "video/vnd.dlna.mpeg-tts"; break; case ".user": contentType = "text/plain"; break; case ".vb": contentType = "text/plain"; break; case ".vbdproj": contentType = "text/plain"; break; case ".vbproj": contentType = "text/plain"; break; case ".vcproj": contentType = "Application/xml"; break; case ".vcxproj": contentType = "Application/xml"; break; case ".vddproj": contentType = "text/plain"; break; case ".vdp": contentType = "text/plain"; break; case ".vdproj": contentType = "text/plain"; break; case ".vdx": contentType = "application/vnd.visio"; break; case ".vscontent": contentType = "application/xml"; break; case ".vsct": contentType = "text/xml"; break; case ".vsd": contentType = "application/vnd.visio"; break; case ".vsi": contentType = "application/ms-vsi"; break; case ".vsix": contentType = "application/vsix"; break; case ".vsixlangpack": contentType = "text/xml"; break; case ".vsixmanifest": contentType = "text/xml"; break; case ".vsl": contentType = "application/vnd.visio"; break; case ".vsmdi": contentType = "application/xml"; break; case ".vspscc": contentType = "text/plain"; break; case ".vss": contentType = "application/vnd.visio"; break; case ".vsscc": contentType = "text/plain"; break; case ".vssettings": contentType = "text/xml"; break; case ".vssscc": contentType = "text/plain"; break; case ".vst": contentType = "application/vnd.visio"; break; case ".vstemplate": contentType = "text/xml"; break; case ".vsto": contentType = "application/x-ms-vsto"; break; case ".vsu": contentType = "application/vnd.visio"; break; case ".vsw": contentType = "application/vnd.visio"; break; case ".vsx": contentType = "application/vnd.visio"; break; case ".vtx": contentType = "application/vnd.visio"; break; case ".wax": contentType = "audio/x-ms-wax"; break; case ".wbk": contentType = "application/msword"; break; case ".wdp": contentType = "image/vnd.ms-photo"; break; case ".webtest": contentType = "application/xml"; break; case ".wiq": contentType = "application/xml"; break; case ".wiz": contentType = "application/msword"; break; case ".wm": contentType = "video/x-ms-wm"; break; case ".wma": contentType = "audio/x-ms-wma"; break; case ".wmd": contentType = "application/x-ms-wmd"; break; case ".wmv": contentType = "video/x-ms-wmv"; break; case ".wmx": contentType = "video/x-ms-wmx"; break; case ".wmz": contentType = "application/x-ms-wmz"; break; case ".wpl": contentType = "application/vnd.ms-wpl"; break; case ".wsc": contentType = "text/scriptlet"; break; case ".wsdl": contentType = "application/xml"; break; case ".wvx": contentType = "video/x-ms-wvx"; break; case ".xaml": contentType = "application/xaml+xml"; break; case ".xbap": contentType = "application/x-ms-xbap"; break; case ".xbrl": contentType = "text/xml"; break; case ".xdp": contentType = "application/vnd.adobe.xdp+xml"; break; case ".xdr": contentType = "application/xml"; break; case ".xej": contentType = "application/xej+xml"; break; case ".xel": contentType = "application/xel+xml"; break; case ".xesc": contentType = "application/x-ms-wmv"; break; case ".xfd": contentType = "application/vnd.adobe.xfd+xml"; break; case ".xfdf": contentType = "application/vnd.adobe.xfdf"; break; case ".xht": contentType = "application/xhtml+xml"; break; case ".xhtml": contentType = "application/xhtml+xml"; break; case ".xlam": contentType = "application/vnd.ms-excel.addin.macroEnabled.12"; break; case ".xlk": contentType = "application/vnd.ms-excel"; break; case ".xll": contentType = "application/vnd.ms-excel"; break; case ".xlsb": contentType = "application/vnd.ms-excel.sheet.binary.macroEnabled.12"; break; case ".xlsm": contentType = "application/vnd.ms-excel.sheet.macroEnabled.12"; break; case ".xlsx": contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; break; case ".xltm": contentType = "application/vnd.ms-excel.template.macroEnabled.12"; break; case ".xltx": contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template"; break; case ".xml": contentType = "application/xml"; break; case ".xmta": contentType = "application/xml"; break; case ".xpr": contentType = "image/xpr"; break; case ".xps": contentType = "application/vnd.ms-xpsdocument"; break; case ".xrm-ms": contentType = "text/xml"; break; case ".xsc": contentType = "application/xml"; break; case ".xsd": contentType = "application/xml"; break; case ".xsl": contentType = "text/xml"; break; case ".xslt": contentType = "application/xml"; break; case ".xss": contentType = "application/xml"; break; case ".323": contentType = "text/h323"; break; case ".acx": contentType = "application/internet-property-stream"; break; case ".ai": contentType = "application/postscript"; break; case ".aif": contentType = "audio/x-aiff"; break; case ".aifc": contentType = "audio/x-aiff"; break; case ".aiff": contentType = "audio/x-aiff"; break; case ".asf": contentType = "video/x-ms-asf"; break; case ".asr": contentType = "video/x-ms-asf"; break; case ".asx": contentType = "video/x-ms-asf"; break; case ".au": contentType = "audio/basic"; break; case ".avi": contentType = "video/x-msvideo"; break; case ".axs": contentType = "application/olescript"; break; case ".bas": contentType = "text/plain"; break; case ".bcpio": contentType = "application/x-bcpio"; break; case ".bin": contentType = "application/octet-stream"; break; case ".bmp": contentType = "image/bmp"; break; case ".c": contentType = "text/plain"; break; case ".cat": contentType = "application/vnd.ms-pkiseccat"; break; case ".cdf": contentType = "application/x-cdf"; break; case ".cer": contentType = "application/x-x509-ca-cert"; break; case ".class": contentType = "application/octet-stream"; break; case ".clp": contentType = "application/x-msclip"; break; case ".cmx": contentType = "image/x-cmx"; break; case ".cod": contentType = "image/cis-cod"; break; case ".cpio": contentType = "application/x-cpio"; break; case ".crd": contentType = "application/x-mscardfile"; break; case ".crl": contentType = "application/pkix-crl"; break; case ".crt": contentType = "application/x-x509-ca-cert"; break; case ".csh": contentType = "application/x-csh"; break; case ".css": contentType = "text/css"; break; case ".dcr": contentType = "application/x-director"; break; case ".der": contentType = "application/x-x509-ca-cert"; break; case ".dir": contentType = "application/x-director"; break; case ".dll": contentType = "application/x-msdownload"; break; case ".dms": contentType = "application/octet-stream"; break; case ".doc": contentType = "application/msword"; break; case ".dot": contentType = "application/msword"; break; case ".dvi": contentType = "application/x-dvi"; break; case ".dxr": contentType = "application/x-director"; break; case ".eps": contentType = "application/postscript"; break; case ".etx": contentType = "text/x-setext"; break; case ".evy": contentType = "application/envoy"; break; case ".exe": contentType = "application/octet-stream"; break; case ".fif": contentType = "application/fractals"; break; case ".flr": contentType = "x-world/x-vrml"; break; case ".gif": contentType = "image/gif"; break; case ".gtar": contentType = "application/x-gtar"; break; case ".gz": contentType = "application/x-gzip"; break; case ".h": contentType = "text/plain"; break; case ".hdf": contentType = "application/x-hdf"; break; case ".hlp": contentType = "application/winhlp"; break; case ".hqx": contentType = "application/mac-binhex40"; break; case ".hta": contentType = "application/hta"; break; case ".htc": contentType = "text/x-component"; break; case ".htm": contentType = "text/html"; break; case ".html": contentType = "text/html"; break; case ".htt": contentType = "text/webviewhtml"; break; case ".ico": contentType = "image/x-icon"; break; case ".ief": contentType = "image/ief"; break; case ".iii": contentType = "application/x-iphone"; break; case ".ins": contentType = "application/x-internet-signup"; break; case ".isp": contentType = "application/x-internet-signup"; break; case ".jfif": contentType = "image/pipeg"; break; case ".jpe": contentType = "image/jpeg"; break; case ".jpeg": contentType = "image/jpeg"; break; case ".jpg": contentType = "image/jpeg"; break; case ".js": contentType = "application/x-javascript"; break; case ".latex": contentType = "application/x-latex"; break; case ".lha": contentType = "application/octet-stream"; break; case ".lsf": contentType = "video/x-la-asf"; break; case ".lsx": contentType = "video/x-la-asf"; break; case ".lzh": contentType = "application/octet-stream"; break; case ".m13": contentType = "application/x-msmediaview"; break; case ".m14": contentType = "application/x-msmediaview"; break; case ".m3u": contentType = "audio/x-mpegurl"; break; case ".man": contentType = "application/x-troff-man"; break; case ".mdb": contentType = "application/x-msaccess"; break; case ".me": contentType = "application/x-troff-me"; break; case ".mht": contentType = "message/rfc822"; break; case ".mhtml": contentType = "message/rfc822"; break; case ".mid": contentType = "audio/mid"; break; case ".mny": contentType = "application/x-msmoney"; break; case ".mov": contentType = "video/quicktime"; break; case ".movie": contentType = "video/x-sgi-movie"; break; case ".mp2": contentType = "video/mpeg"; break; case ".mp3": contentType = "audio/mpeg"; break; case ".mpa": contentType = "video/mpeg"; break; case ".mpe": contentType = "video/mpeg"; break; case ".mpeg": contentType = "video/mpeg"; break; case ".mpg": contentType = "video/mpeg"; break; case ".mpp": contentType = "application/vnd.ms-project"; break; case ".mpv2": contentType = "video/mpeg"; break; case ".ms": contentType = "application/x-troff-ms"; break; case ".msg": contentType = "application/vnd.ms-outlook"; break; case ".mvb": contentType = "application/x-msmediaview"; break; case ".nc": contentType = "application/x-netcdf"; break; case ".nws": contentType = "message/rfc822"; break; case ".oda": contentType = "application/oda"; break; case ".p10": contentType = "application/pkcs10"; break; case ".p12": contentType = "application/x-pkcs12"; break; case ".p7b": contentType = "application/x-pkcs7-certificates"; break; case ".p7c": contentType = "application/x-pkcs7-mime"; break; case ".p7m": contentType = "application/x-pkcs7-mime"; break; case ".p7r": contentType = "application/x-pkcs7-certreqresp"; break; case ".p7s": contentType = "application/x-pkcs7-signature"; break; case ".pbm": contentType = "image/x-portable-bitmap"; break; case ".pdf": contentType = "application/pdf"; break; case ".pfx": contentType = "application/x-pkcs12"; break; case ".pgm": contentType = "image/x-portable-graymap"; break; case ".pko": contentType = "application/ynd.ms-pkipko"; break; case ".pma": contentType = "application/x-perfmon"; break; case ".pmc": contentType = "application/x-perfmon"; break; case ".pml": contentType = "application/x-perfmon"; break; case ".pmr": contentType = "application/x-perfmon"; break; case ".pmw": contentType = "application/x-perfmon"; break; case ".pnm": contentType = "image/x-portable-anymap"; break; case ".pot": contentType = "application/vnd.ms-powerpoint"; break; case ".pot,": contentType = "application/vnd.ms-powerpoint"; break; case ".ppm": contentType = "image/x-portable-pixmap"; break; case ".pps": contentType = "application/vnd.ms-powerpoint"; break; case ".ppt": contentType = "application/vnd.ms-powerpoint"; break; case ".prf": contentType = "application/pics-rules"; break; case ".ps": contentType = "application/postscript"; break; case ".pub": contentType = "application/x-mspublisher"; break; case ".qt": contentType = "video/quicktime"; break; case ".ra": contentType = "audio/x-pn-realaudio"; break; case ".ram": contentType = "audio/x-pn-realaudio"; break; case ".ras": contentType = "image/x-cmu-raster"; break; case ".rgb": contentType = "image/x-rgb"; break; case ".rmi": contentType = "audio/mid"; break; case ".roff": contentType = "application/x-troff"; break; case ".rtf": contentType = "application/rtf"; break; case ".rtx": contentType = "text/richtext"; break; case ".scd": contentType = "application/x-msschedule"; break; case ".sct": contentType = "text/scriptlet"; break; case ".setpay": contentType = "application/set-payment-initiation"; break; case ".setreg": contentType = "application/set-registration-initiation"; break; case ".sh": contentType = "application/x-sh"; break; case ".shar": contentType = "application/x-shar"; break; case ".sit": contentType = "application/x-stuffit"; break; case ".snd": contentType = "audio/basic"; break; case ".spc": contentType = "application/x-pkcs7-certificates"; break; case ".spl": contentType = "application/futuresplash"; break; case ".src": contentType = "application/x-wais-source"; break; case ".sst": contentType = "application/vnd.ms-pkicertstore"; break; case ".stl": contentType = "application/vnd.ms-pkistl"; break; case ".stm": contentType = "text/html"; break; case ".sv4cpio": contentType = "application/x-sv4cpio"; break; case ".sv4crc": contentType = "application/x-sv4crc"; break; case ".svg": contentType = "image/svg+xml"; break; case ".swf": contentType = "application/x-shockwave-flash"; break; case ".t": contentType = "application/x-troff"; break; case ".tar": contentType = "application/x-tar"; break; case ".tcl": contentType = "application/x-tcl"; break; case ".tex": contentType = "application/x-tex"; break; case ".texi": contentType = "application/x-texinfo"; break; case ".texinfo": contentType = "application/x-texinfo"; break; case ".tgz": contentType = "application/x-compressed"; break; case ".tif": contentType = "image/tiff"; break; case ".tiff": contentType = "image/tiff"; break; case ".tr": contentType = "application/x-troff"; break; case ".trm": contentType = "application/x-msterminal"; break; case ".tsv": contentType = "text/tab-separated-values"; break; case ".txt": contentType = "text/plain"; break; case ".uls": contentType = "text/iuls"; break; case ".ustar": contentType = "application/x-ustar"; break; case ".vcf": contentType = "text/x-vcard"; break; case ".vrml": contentType = "x-world/x-vrml"; break; case ".wav": contentType = "audio/x-wav"; break; case ".wcm": contentType = "application/vnd.ms-works"; break; case ".wdb": contentType = "application/vnd.ms-works"; break; case ".wks": contentType = "application/vnd.ms-works"; break; case ".wmf": contentType = "application/x-msmetafile"; break; case ".wps": contentType = "application/vnd.ms-works"; break; case ".wri": contentType = "application/x-mswrite"; break; case ".wrl": contentType = "x-world/x-vrml"; break; case ".wrz": contentType = "x-world/x-vrml"; break; case ".xaf": contentType = "x-world/x-vrml"; break; case ".xbm": contentType = "image/x-xbitmap"; break; case ".xla": contentType = "application/vnd.ms-excel"; break; case ".xlc": contentType = "application/vnd.ms-excel"; break; case ".xlm": contentType = "application/vnd.ms-excel"; break; case ".xls": contentType = "application/vnd.ms-excel"; break; case ".xlt": contentType = "application/vnd.ms-excel"; break; case ".xlw": contentType = "application/vnd.ms-excel"; break; case ".xof": contentType = "x-world/x-vrml"; break; case ".xpm": contentType = "image/x-xpixmap"; break; case ".xwd": contentType = "image/x-xwindowdump"; break; case ".z": contentType = "application/x-compress"; break; case ".zip": contentType = "application/zip"; break; default: contentType = ""; break; } #endregion return contentType; } public static T GetValueOrDefault<T>(this IDataRecord row, string fieldName) { int ordinal = row.GetOrdinal(fieldName); return row.GetValueOrDefault<T>(ordinal); } public static T GetValueOrDefault<T>(this IDataRecord row, int ordinal) { return (T) (row.IsDBNull(ordinal) ? default(T) : row.GetValue(ordinal)); } public static byte[] StreamToBytes(this Stream input) { int capacity = input.CanSeek ? (int) input.Length : 0; using (MemoryStream output = new MemoryStream(capacity)) { int readLength; byte[] buffer = new byte[4096]; do { readLength = input.Read(buffer, 0, buffer.Length); output.Write(buffer, 0, readLength); } while (readLength != 0); return output.ToArray(); } } private static IList<string> SplitIntoChunks(this string text, int chunkSize) { List<string> chunks = new List<string>(); int offset = 0; while (offset < text.Length) { int size = Math.Min(chunkSize, text.Length - offset); chunks.Add(text.Substring(offset, size)); offset += size; } return chunks; } } /// <summary> /// /// </summary> public enum RunState { /// <summary> /// /// </summary> Idle = 0, /// <summary> /// /// </summary> Running } /// <summary> /// /// </summary> public enum PortMode { /// <summary> /// /// </summary> FirstAvailable = 0, /// <summary> /// /// </summary> Specific } /// <summary> /// /// </summary> public enum ErrorField { /// <summary> /// /// </summary> None, /// <summary> /// /// </summary> ApplicationPath, /// <summary> /// /// </summary> VirtualPath, /// <summary> /// /// </summary> HostName, /// <summary> /// /// </summary> IsAddHost, /// <summary> /// /// </summary> // ReSharper disable InconsistentNaming IPAddress, // ReSharper restore InconsistentNaming /// <summary> /// /// </summary> // ReSharper disable InconsistentNaming IPAddressAny, // ReSharper restore InconsistentNaming /// <summary> /// /// </summary> // ReSharper disable InconsistentNaming IPAddressLoopBack, // ReSharper restore InconsistentNaming /// <summary> /// /// </summary> Port, /// <summary> /// /// </summary> PortRangeStart, /// <summary> /// /// </summary> PortRangeEnd, /// <summary> /// /// </summary> PortRange } /// <summary> /// /// </summary> // ReSharper disable InconsistentNaming public enum IPMode // ReSharper restore InconsistentNaming { /// <summary> /// /// </summary> Loopback = 0, /// <summary> /// /// </summary> Any, /// <summary> /// /// </summary> Specific } /// <summary> /// /// </summary> public enum RunMode { /// <summary> /// /// </summary> Server, /// <summary> /// /// </summary> Hostsfile } /// <summary> /// /// </summary> internal class CassiniException : Exception { public CassiniException(string message, ErrorField field, Exception innerException) : base(message, innerException) { Field = field; } public CassiniException(string message, ErrorField field) : this(message, field, null) { } public ErrorField Field { get; set; } } }
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) 2010 Sky Sanders. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; using System.Web; #endregion namespace SimpleWebServer { /// <summary> /// /// </summary> public class Connection : MarshalByRefObject { private const int HttpForbidden = 403; // ReSharper disable InconsistentNaming private const int HttpOK = 200; // ReSharper restore InconsistentNaming private readonly MemoryStream _responseContent; /// <summary> /// /// </summary> public List<string> Plugins = new List<string>(); private readonly Server _server; private Socket _socket; internal Connection(Server server, Socket socket) { Plugins = server.Plugins; Id = Guid.NewGuid(); _responseContent = new MemoryStream(); _server = server; _socket = socket; } /// <summary> /// /// </summary> public bool Connected { get { return _socket.Connected; } } /// <summary> /// /// </summary> public Guid Id { get; private set; } /// <summary> /// /// </summary> // ReSharper disable InconsistentNaming public string LocalIP // ReSharper restore InconsistentNaming { get { IPEndPoint ep = (IPEndPoint) _socket.LocalEndPoint; return (ep != null && ep.Address != null) ? ep.Address.ToString() : "127.0.0.1"; } } // ReSharper disable InconsistentNaming /// <summary> /// /// </summary> public string RemoteIP // ReSharper restore InconsistentNaming { get { IPEndPoint ep = (IPEndPoint) _socket.RemoteEndPoint; return (ep != null && ep.Address != null) ? ep.Address.ToString() : "127.0.0.1"; } } /// <summary> /// /// </summary> public void Close() { try { _socket.Shutdown(SocketShutdown.Both); _socket.Close(); } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { } finally { _socket = null; } } /// <summary> /// </summary> public override object InitializeLifetimeService() { return null; } /// <summary> /// /// </summary> /// <param name="maxBytes"></param> /// <returns></returns> public byte[] ReadRequestBytes(int maxBytes) { try { if (WaitForRequestBytes() == 0) { return null; } int numBytes = _socket.Available; if (numBytes > maxBytes) { numBytes = maxBytes; } int numReceived = 0; byte[] buffer = new byte[numBytes]; if (numBytes > 0) { numReceived = _socket.Receive(buffer, 0, numBytes, SocketFlags.None); } if (numReceived < numBytes) { byte[] tempBuffer = new byte[numReceived]; if (numReceived > 0) { Buffer.BlockCopy(buffer, 0, tempBuffer, 0, numReceived); } buffer = tempBuffer; } return buffer; } catch { return null; } } /// <summary> /// /// </summary> /// <returns></returns> public int WaitForRequestBytes() { int availBytes = 0; try { if (_socket.Available == 0) { _socket.Poll(100000, SelectMode.SelectRead); if (_socket.Available == 0 && _socket.Connected) { _socket.Poll(30000000, SelectMode.SelectRead); } } availBytes = _socket.Available; } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { } return availBytes; } /// <summary> /// /// </summary> public void Write100Continue() { WriteEntireResponseFromString(100, null, null, true); } internal void Write200Continue() { WriteEntireResponseFromString(200, null, string.Empty, true); } /// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="offset"></param> /// <param name="length"></param> public void WriteBody(byte[] data, int offset, int length) { try { _responseContent.Write(data, 0, data.Length); _socket.Send(data, offset, length, SocketFlags.None); } catch (SocketException) { } } /// <summary> /// /// </summary> /// <param name="fileName"></param> /// <param name="keepAlive"></param> public void WriteEntireResponseFromFile(String fileName, bool keepAlive) { if (!File.Exists(fileName)) { WriteErrorAndClose(404); return; } // Deny the request if the contentType cannot be recognized. string contentType = CommonExtensions.GetContentType(fileName); //TODO: i am pretty sure this is unnecessary if (contentType == null) { WriteErrorAndClose(HttpForbidden); return; } string contentTypeHeader = "Content-Type: " + contentType + "\r\n"; bool completed = false; FileStream fs = null; try { fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); int len = (int) fs.Length; byte[] fileBytes = new byte[len]; int bytesRead = fs.Read(fileBytes, 0, len); String headers = MakeResponseHeaders(HttpOK, contentTypeHeader, bytesRead, keepAlive); _socket.Send(Encoding.UTF8.GetBytes(headers)); _socket.Send(fileBytes, 0, bytesRead, SocketFlags.None); completed = true; } catch (SocketException) { } finally { if (!keepAlive || !completed) { Close(); } if (fs != null) { fs.Close(); } } } /// <summary> /// /// </summary> /// <param name="statusCode"></param> /// <param name="extraHeaders"></param> /// <param name="body"></param> /// <param name="keepAlive"></param> public void WriteEntireResponseFromString(int statusCode, String extraHeaders, String body, bool keepAlive) { try { int bodyLength = (body != null) ? Encoding.UTF8.GetByteCount(body) : 0; string headers = MakeResponseHeaders(statusCode, extraHeaders, bodyLength, keepAlive); _socket.Send(Encoding.UTF8.GetBytes(headers + body)); } catch (SocketException) { } finally { if (!keepAlive) { Close(); } } } /// <summary> /// /// </summary> /// <param name="statusCode"></param> /// <param name="message"></param> public void WriteErrorAndClose(int statusCode, string message) { WriteEntireResponseFromString(statusCode, null, GetErrorResponseBody(statusCode, message), false); } /// <summary> /// /// </summary> /// <param name="statusCode"></param> public void WriteErrorAndClose(int statusCode) { WriteErrorAndClose(statusCode, null); } /// <summary> /// /// </summary> /// <param name="statusCode"></param> /// <param name="extraHeaders"></param> public void WriteErrorWithExtraHeadersAndKeepAlive(int statusCode, string extraHeaders) { WriteEntireResponseFromString(statusCode, extraHeaders, GetErrorResponseBody(statusCode, null), true); } /// <summary> /// /// </summary> /// <param name="statusCode"></param> /// <param name="extraHeaders"></param> public void WriteHeaders(int statusCode, String extraHeaders) { string headers = MakeResponseHeaders(statusCode, extraHeaders, -1, false); try { _socket.Send(Encoding.UTF8.GetBytes(headers)); } catch (SocketException) { } } private string GetErrorResponseBody(int statusCode, string message) { string body = Messages.FormatErrorMessageBody(statusCode, _server.VirtualPath); if (!string.IsNullOrEmpty(message)) { body += "\r\n<!--\r\n" + message + "\r\n-->"; } return body; } //private void InitializeLogInfo() //{ // _requestLog = new LogInfo // { // Created = DateTime.Now, // ConversationId = Id, // RowType = 1, // Identity = _server.GetProcessUser(), // PhysicalPath = _server.PhysicalPath // }; // _responseLog = new LogInfo // { // ConversationId = Id, // RowType = 2 // }; //} private static string MakeResponseHeaders(int statusCode, string moreHeaders, int contentLength, bool keepAlive) { StringBuilder sb = new StringBuilder(); sb.Append("HTTP/1.1 " + statusCode + " " + HttpWorkerRequest.GetStatusDescription(statusCode) + "\r\n"); sb.Append("Server: Cassini/" + Messages.VersionString + "\r\n"); sb.Append("Date: " + DateTime.Now.ToUniversalTime().ToString("R", DateTimeFormatInfo.InvariantInfo) + "\r\n"); if (contentLength >= 0) { sb.Append("Content-Length: " + contentLength + "\r\n"); } if (moreHeaders != null) { sb.Append(moreHeaders); } if (!keepAlive) { sb.Append("Connection: Close\r\n"); } sb.Append("\r\n"); return sb.ToString(); } } }
#region using System; using System.Globalization; using System.Security.Permissions; using System.Security.Principal; using System.Threading; using System.Web; using System.Web.Hosting; #endregion namespace SimpleWebServer { public class Host : MarshalByRefObject, IRegisteredObject { private bool _disableDirectoryListing; private string _installPath; private string _lowerCasedClientScriptPathWithTrailingSlash; private string _lowerCasedVirtualPath; private string _lowerCasedVirtualPathWithTrailingSlash; private volatile int _pendingCallsCount; private string _physicalClientScriptPath; private string _physicalPath; private int _port; private bool _requireAuthentication; private Server _server; private string _virtualPath; public AppDomain AppDomain { get { return AppDomain.CurrentDomain; } } public Host() { HostingEnvironment.RegisterObject(this); } public bool DisableDirectoryListing { get { return _disableDirectoryListing; } } public string InstallPath { get { return _installPath; } } public string NormalizedClientScriptPath { get { return _lowerCasedClientScriptPathWithTrailingSlash; } } public string NormalizedVirtualPath { get { return _lowerCasedVirtualPathWithTrailingSlash; } } public string PhysicalClientScriptPath { get { return _physicalClientScriptPath; } } public string PhysicalPath { get { return _physicalPath; } } public int Port { get { return _port; } } public bool RequireAuthentication { get { return _requireAuthentication; } } public string VirtualPath { get { return _virtualPath; } } #region IRegisteredObject Members void IRegisteredObject.Stop(bool immediate) { // Unhook the Host so Server will process the requests in the new appdomain. if (_server != null) { _server.HostStopped(); } // Make sure all the pending calls complete before this Object is unregistered. WaitForPendingCallsToFinish(); HostingEnvironment.UnregisterObject(this); Thread.Sleep(100); HttpRuntime.Close(); Thread.Sleep(100); } #endregion public void Configure(Server server, int port, string virtualPath, string physicalPath, bool requireAuthentication) { Configure(server, port, virtualPath, physicalPath, requireAuthentication, false); } public void Configure(Server server, int port, string virtualPath, string physicalPath) { Configure(server, port, virtualPath, physicalPath, false, false); } public void Configure(Server server, int port, string virtualPath, string physicalPath, bool requireAuthentication, bool disableDirectoryListing) { _server = server; _port = port; _installPath = null; _virtualPath = virtualPath; _requireAuthentication = requireAuthentication; _disableDirectoryListing = disableDirectoryListing; _lowerCasedVirtualPath = CultureInfo.InvariantCulture.TextInfo.ToLower(_virtualPath); _lowerCasedVirtualPathWithTrailingSlash = virtualPath.EndsWith("/", StringComparison.Ordinal) ? virtualPath : virtualPath + "/"; _lowerCasedVirtualPathWithTrailingSlash = CultureInfo.InvariantCulture.TextInfo.ToLower(_lowerCasedVirtualPathWithTrailingSlash); _physicalPath = physicalPath; _physicalClientScriptPath = HttpRuntime.AspClientScriptPhysicalPath + "\\"; _lowerCasedClientScriptPathWithTrailingSlash = CultureInfo.InvariantCulture.TextInfo.ToLower(HttpRuntime.AspClientScriptVirtualPath + "/"); } public SecurityIdentifier GetProcessSid() { using (WindowsIdentity identity = new WindowsIdentity(_server.GetProcessToken())) { return identity.User; } } public IntPtr GetProcessToken() { new SecurityPermission(PermissionState.Unrestricted).Assert(); return _server.GetProcessToken(); } public string GetProcessUser() { return _server.GetProcessUser(); } public override object InitializeLifetimeService() { // never expire the license return null; } public bool IsVirtualPathAppPath(string path) { if (path == null) { return false; } path = CultureInfo.InvariantCulture.TextInfo.ToLower(path); return (path == _lowerCasedVirtualPath || path == _lowerCasedVirtualPathWithTrailingSlash); } public bool IsVirtualPathInApp(string path, out bool isClientScriptPath) { isClientScriptPath = false; if (path == null) { return false; } if (_virtualPath == "/" && path.StartsWith("/", StringComparison.Ordinal)) { if (path.StartsWith(_lowerCasedClientScriptPathWithTrailingSlash, StringComparison.Ordinal)) { isClientScriptPath = true; } return true; } path = CultureInfo.InvariantCulture.TextInfo.ToLower(path); if (path.StartsWith(_lowerCasedVirtualPathWithTrailingSlash, StringComparison.Ordinal)) { return true; } if (path == _lowerCasedVirtualPath) { return true; } if (path.StartsWith(_lowerCasedClientScriptPathWithTrailingSlash, StringComparison.Ordinal)) { isClientScriptPath = true; return true; } return false; } public bool IsVirtualPathInApp(String path) { bool isClientScriptPath; return IsVirtualPathInApp(path, out isClientScriptPath); } public void ProcessRequest(Connection conn,string dfPage) { // Add a pending call to make sure our thread doesn't get killed AddPendingCall(); try { new Request(_server, this, conn, dfPage).Process(); } finally { RemovePendingCall(); } } [SecurityPermission(SecurityAction.Assert, Unrestricted = true)] public void Shutdown() { HostingEnvironment.InitiateShutdown(); } private void AddPendingCall() { //TODO: investigate this issue - ref var not volitile #pragma warning disable 0420 Interlocked.Increment(ref _pendingCallsCount); #pragma warning restore 0420 } private void RemovePendingCall() { //TODO: investigate this issue - ref var not volitile #pragma warning disable 0420 Interlocked.Decrement(ref _pendingCallsCount); #pragma warning restore 0420 } private void WaitForPendingCallsToFinish() { for (; ; ) { if (_pendingCallsCount <= 0) { break; } Thread.Sleep(250); } } } }
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) 2010 Sky Sanders. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System; using System.Runtime.InteropServices; #endregion namespace SimpleWebServer { internal static class Interop { #region Structs [DllImport("SECUR32.DLL", CharSet = CharSet.Unicode)] public static extern int AcceptSecurityContext(ref SecHandle phCredential, IntPtr phContext, ref SecBufferDesc pInput, uint fContextReq, uint TargetDataRep, ref SecHandle phNewContext, ref SecBufferDesc pOutput, ref uint pfContextAttr, ref long ptsTimeStamp); [DllImport("SECUR32.DLL", CharSet = CharSet.Unicode)] public static extern int AcquireCredentialsHandle(string pszPrincipal, string pszPackage, uint fCredentialUse, IntPtr pvLogonID, IntPtr pAuthData, IntPtr pGetKeyFn, IntPtr pvGetKeyArgument, ref SecHandle phCredential, ref long ptsExpiry); [DllImport("KERNEL32.DLL", CharSet = CharSet.Unicode)] public static extern int CloseHandle(IntPtr phToken); [DllImport("SECUR32.DLL", CharSet = CharSet.Unicode)] public static extern int DeleteSecurityContext(ref SecHandle phContext); /// <summary> /// FIX: #12506 /// </summary> [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)] public static extern int FindMimeFromData(IntPtr pBC, [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 3)] byte[] pBuffer, int cbSize, [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed, int dwMimeFlags, out IntPtr ppwzMimeOut, int dwReserved); [DllImport("SECUR32.DLL", CharSet = CharSet.Unicode)] public static extern int FreeCredentialsHandle(ref SecHandle phCredential); [DllImport("kernel32.dll", EntryPoint = "GetConsoleScreenBufferInfo", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int GetConsoleScreenBufferInfo(int hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); [DllImport("KERNEL32.DLL", SetLastError = true)] public static extern IntPtr GetCurrentThread(); [DllImport("kernel32.dll", EntryPoint = "GetStdHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int GetStdHandle(int nStdHandle); [DllImport("ADVAPI32.DLL", SetLastError = true)] public static extern bool ImpersonateSelf(int level); [DllImport("ADVAPI32.DLL", SetLastError = true)] public static extern int OpenThreadToken(IntPtr thread, int access, bool openAsSelf, ref IntPtr hToken); [DllImport("SECUR32.DLL", CharSet = CharSet.Unicode)] public static extern int QuerySecurityContextToken(ref SecHandle phContext, ref IntPtr phToken); [DllImport("ADVAPI32.DLL", SetLastError = true)] public static extern int RevertToSelf(); #region Nested type: CONSOLE_SCREEN_BUFFER_INFO public struct CONSOLE_SCREEN_BUFFER_INFO { internal COORD dwCursorPosition; internal COORD dwMaximumWindowSize; internal COORD dwSize; internal SMALL_RECT srWindow; internal Int16 wAttributes; } #endregion #region Nested type: COORD public struct COORD { internal Int16 x; internal Int16 y; } #endregion #region Nested type: SecBuffer [StructLayout(LayoutKind.Sequential)] public struct SecBuffer { // ReSharper disable InconsistentNaming public uint cbBuffer; public uint BufferType; public IntPtr pvBuffer; // ReSharper restore InconsistentNaming } #endregion #region Nested type: SecBufferDesc [StructLayout(LayoutKind.Sequential)] public struct SecBufferDesc { // ReSharper disable InconsistentNaming public uint ulVersion; public uint cBuffers; public IntPtr pBuffers; // ReSharper restore InconsistentNaming } #endregion #region Nested type: SecHandle [StructLayout(LayoutKind.Sequential)] public struct SecHandle { // ReSharper disable InconsistentNaming public IntPtr dwLower; public IntPtr dwUpper; // ReSharper restore InconsistentNaming } #endregion #region Nested type: SMALL_RECT public struct SMALL_RECT { internal Int16 Bottom; internal Int16 Left; internal Int16 Right; internal Int16 Top; } #endregion #endregion } }
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) Microsoft Corporation. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System.IO; using System.Text; using System.Web; #endregion namespace SimpleWebServer { /// <summary> /// TODO: get this into resources /// </summary> internal static class Messages { private const string _dirListingDirFormat = @"{0,38:dddd, MMMM dd, yyyy hh:mm tt} <dir> <A href=""{1}/"">{2}</A> "; private const string _dirListingFileFormat = @"{0,38:dddd, MMMM dd, yyyy hh:mm tt} {1,12:n0} <A href=""{2}"">{3}</A> "; private const string _dirListingFormat1 = @"<html> <head> <title>Directory Listing -- {0}</title> "; private const string _dirListingFormat2 = @" </head> <body bgcolor=""white""> <h2> <i>Directory Listing -- {0}</i> </h2></span> <hr width=100% size=1 color=silver> <PRE> "; private const string _dirListingParentFormat = @"<A href=""{0}"">[To Parent Directory]</A> "; private const string _httpErrorFormat1 = @"<html> <head> <title>{0}</title> "; private const string _httpStyle = @" <style> body {font-family:""Verdana"";font-weight:normal;font-size: 8pt;color:black;} p {font-family:""Verdana"";font-weight:normal;color:black;margin-top: -5px} b {font-family:""Verdana"";font-weight:bold;color:black;margin-top: -5px} h1 { font-family:""Verdana"";font-weight:normal;font-size:18pt;color:red } h2 { font-family:""Verdana"";font-weight:normal;font-size:14pt;color:maroon } pre {font-family:""Lucida Console"";font-size: 8pt} .marker {font-weight: bold; color: black;text-decoration: none;} .version {color: gray;} .error {margin-bottom: 10px;} .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; } </style> "; private static readonly string _dirListingTail = @"</PRE> <hr width=100% size=1 color=silver> <b>Version Information:</b> CassiniDev Web Server " + VersionString + @" </font> </body> </html> "; private static readonly string _httpErrorFormat2 = @" </head> <body bgcolor=""white""> <span><h1>Server Error in '{0}' Application.<hr width=100% size=1 color=silver></h1> <h2> <i>HTTP Error {1} - {2}.</i> </h2></span> <hr width=100% size=1 color=silver> <b>Version Information:</b> CassiniDev Web Server " + VersionString + @" </font> </body> </html> "; public static string VersionString = typeof (Server).Assembly.GetName().Version.ToString(); public static string FormatDirectoryListing(string dirPath, string parentPath, FileSystemInfo[] elements) { StringBuilder sb = new StringBuilder(); sb.Append(string.Format(_dirListingFormat1, dirPath)); sb.Append(_httpStyle); sb.Append(string.Format(_dirListingFormat2, dirPath)); if (parentPath != null) { if (!parentPath.EndsWith("/")) { parentPath += "/"; } sb.Append(string.Format(_dirListingParentFormat, parentPath)); } if (elements != null) { for (int i = 0; i < elements.Length; i++) { if (elements[i] is FileInfo) { FileInfo fi = (FileInfo) elements[i]; sb.Append(string.Format(_dirListingFileFormat, fi.LastWriteTime, fi.Length, fi.Name, fi.Name)); } else if (elements[i] is DirectoryInfo) { DirectoryInfo di = (DirectoryInfo) elements[i]; sb.Append(string.Format(_dirListingDirFormat, di.LastWriteTime, di.Name, di.Name)); } } } sb.Append(_dirListingTail); return sb.ToString(); } public static string FormatErrorMessageBody(int statusCode, string appName) { string desc = HttpWorkerRequest.GetStatusDescription(statusCode); return string.Format(_httpErrorFormat1, desc) + _httpStyle + string.Format(_httpErrorFormat2, appName, statusCode, desc); } } }
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) 2010 Sky Sanders. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Security; using System.Security.Permissions; using System.Text; using System.Web; using System.Web.Hosting; using Microsoft.Win32.SafeHandles; using System.Security.Principal; #endregion namespace SimpleWebServer { public class Request : SimpleWorkerRequest { private const int MaxChunkLength = 64 * 1024; private const int MaxHeaderBytes = 32 * 1024; private static readonly char[] BadPathChars = new[] { '%', '>', '<', ':', '\\' }; private static readonly string[] DefaultFileNames = new[] { "default.aspx", "default.htm", "default.html" }; private static readonly char[] IntToHex = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private static readonly string[] RestrictedDirs = new[] { "/bin", "/app_browsers", "/app_code", "/app_data", "/app_localresources", "/app_globalresources", "/app_webreferences" }; private readonly IStackWalk _connectionPermission = new PermissionSet(PermissionState.Unrestricted); private readonly Host _host; private readonly Server _server; private string _allRawHeaders; private byte[] _body; private int _bodyLength; private Connection _connection; private int _contentLength; // security permission to Assert remoting calls to _connection private int _endHeadersOffset; private string _filePath; private byte[] _headerBytes; private List<ByteString> _headerByteStrings; private bool _headersSent; // parsed request data private bool _isClientScriptPath; private string[] _knownRequestHeaders; private string _path; private string _pathInfo; private string _pathTranslated; private string _protocol; private string _queryString; private byte[] _queryStringBytes; private List<byte[]> _responseBodyBytes; private StringBuilder _responseHeadersBuilder; private int _responseStatus; private bool _specialCaseStaticFileHeaders; private int _startHeadersOffset; private string[][] _unknownRequestHeaders; private string _url; private string _verb; private string _dfPage; public Request(Server server, Host host, Connection connection,string dfPage) : base(String.Empty, String.Empty, null) { _connectionPermission = new PermissionSet(PermissionState.Unrestricted); _server = server; _host = host; _connection = connection; _dfPage = dfPage; } public override void CloseConnection() { _connectionPermission.Assert(); _connection.Close(); } public override void EndOfRequest() { Connection conn = _connection; if (conn != null) { _connection = null; _server.OnRequestEnd(conn); } } public override void FlushResponse(bool finalFlush) { if (_responseStatus == 404 && !_headersSent && finalFlush && _verb == "GET") { // attempt directory listing if (ProcessDirectoryListingRequest()) { return; } } _connectionPermission.Assert(); if (!_headersSent) { _connection.WriteHeaders(_responseStatus, _responseHeadersBuilder.ToString()); _headersSent = true; } foreach (byte[] bytes in _responseBodyBytes) { _connection.WriteBody(bytes, 0, bytes.Length); } _responseBodyBytes = new List<byte[]>(); if (finalFlush) { _connection.Close(); } } public override string GetAppPath() { return _host.VirtualPath; } public override string GetAppPathTranslated() { return _host.PhysicalPath; } public override string GetFilePath() { return _filePath; } public override string GetFilePathTranslated() { return _pathTranslated; } public override string GetHttpVerbName() { return _verb; } public override string GetHttpVersion() { return _protocol; } public override string GetKnownRequestHeader(int index) { return _knownRequestHeaders[index]; } public override string GetLocalAddress() { _connectionPermission.Assert(); return _connection.LocalIP; } public override int GetLocalPort() { return _host.Port; } public override string GetPathInfo() { return _pathInfo; } public override byte[] GetPreloadedEntityBody() { return _body; } public override string GetQueryString() { return _queryString; } public override byte[] GetQueryStringRawBytes() { return _queryStringBytes; } public override string GetRawUrl() { return _url; } public override string GetRemoteAddress() { _connectionPermission.Assert(); return _connection.RemoteIP; } public override int GetRemotePort() { return 0; } public override string GetServerName() { string localAddress = GetLocalAddress(); if (localAddress.Equals("127.0.0.1")) { return "localhost"; } return localAddress; } public override string GetServerVariable(string name) { string processUser = string.Empty; string str2 = name; if (str2 == null) { return processUser; } if (str2 != "ALL_RAW") { if (str2 != "SERVER_PROTOCOL") { if (str2 == "LOGON_USER") { if (GetUserToken() != IntPtr.Zero) { processUser = _host.GetProcessUser(); } return processUser; } if ((str2 == "AUTH_TYPE") && (GetUserToken() != IntPtr.Zero)) { processUser = "NTLM"; } return processUser; } } else { return _allRawHeaders; } return _protocol; } public override string GetUnknownRequestHeader(string name) { int n = _unknownRequestHeaders.Length; for (int i = 0; i < n; i++) { if (string.Compare(name, _unknownRequestHeaders[i][0], StringComparison.OrdinalIgnoreCase) == 0) { return _unknownRequestHeaders[i][1]; } } return null; } public override string[][] GetUnknownRequestHeaders() { return _unknownRequestHeaders; } /////////////////////////////////////////////////////////////////////////////////////////////// // Implementation of HttpWorkerRequest public override string GetUriPath() { return _path; } public Connection GetConnection() { return _connection; } public override bool HeadersSent() { return _headersSent; } public override bool IsClientConnected() { _connectionPermission.Assert(); return _connection.Connected; } public override bool IsEntireEntityBodyIsPreloaded() { return (_contentLength == _bodyLength); } public override string MapPath(string path) { string mappedPath; bool isClientScriptPath; if (string.IsNullOrEmpty(path) || path.Equals("/")) { // asking for the site root mappedPath = _host.VirtualPath == "/" ? _host.PhysicalPath : Environment.SystemDirectory; } else if (_host.IsVirtualPathAppPath(path)) { // application path mappedPath = _host.PhysicalPath; } else if (_host.IsVirtualPathInApp(path, out isClientScriptPath)) { if (isClientScriptPath) { mappedPath = _host.PhysicalClientScriptPath + path.Substring(_host.NormalizedClientScriptPath.Length); } else { // inside app but not the app path itself mappedPath = _host.PhysicalPath + path.Substring(_host.NormalizedVirtualPath.Length); } } else { // outside of app -- make relative to app path if (path.StartsWith("/", StringComparison.Ordinal)) { mappedPath = _host.PhysicalPath + path.Substring(1); } else { mappedPath = _host.PhysicalPath + path; } } mappedPath = mappedPath.Replace('/', '\\'); if (mappedPath.EndsWith("\\", StringComparison.Ordinal) && !mappedPath.EndsWith(":\\", StringComparison.Ordinal)) { mappedPath = mappedPath.Substring(0, mappedPath.Length - 1); } return mappedPath; } [AspNetHostingPermission(SecurityAction.Assert, Level = AspNetHostingPermissionLevel.Medium)] public void Process() { // read the request if (!TryParseRequest()) { return; } // 100 response to POST if (_verb == "POST" && _contentLength > 0 && _bodyLength < _contentLength) { _connection.Write100Continue(); } if (!_host.RequireAuthentication) { // special case for client script if (_isClientScriptPath) { _connection.WriteEntireResponseFromFile( _host.PhysicalClientScriptPath + _path.Substring(_host.NormalizedClientScriptPath.Length), false); return; } // deny access to code, bin, etc. if (IsRequestForRestrictedDirectory()) { _connection.WriteErrorAndClose(403); return; } // special case for a request to a directory (ensure / at the end and process default documents) if (ProcessDirectoryRequest()) { return; } PrepareResponse(); // Hand the processing over to HttpRuntime HttpRuntime.ProcessRequest(this); } } public override int ReadEntityBody(byte[] buffer, int size) { int bytesRead = 0; _connectionPermission.Assert(); byte[] bytes = _connection.ReadRequestBytes(size); if (bytes != null && bytes.Length > 0) { bytesRead = bytes.Length; Buffer.BlockCopy(bytes, 0, buffer, 0, bytesRead); } return bytesRead; } public override void SendCalculatedContentLength(int contentLength) { if (!_headersSent) { _responseHeadersBuilder.Append("Content-Length: "); _responseHeadersBuilder.Append(contentLength.ToString(CultureInfo.InvariantCulture)); _responseHeadersBuilder.Append("\r\n"); } } public override void SendKnownResponseHeader(int index, string value) { if (_headersSent) { return; } switch (index) { case HeaderServer: case HeaderDate: case HeaderConnection: // ignore these return; case HeaderAcceptRanges: // FIX: #14359 if (value != "bytes") { // use this header to detect when we're processing a static file break; } _specialCaseStaticFileHeaders = true; return; case HeaderExpires: case HeaderLastModified: // FIX: #14359 if (!_specialCaseStaticFileHeaders) { // NOTE: Ignore these for static files. These are generated // by the StaticFileHandler, but they shouldn't be. break; } return; // FIX: #12506 case HeaderContentType: string contentType = null; if (value == "application/octet-stream") { // application/octet-stream is default for unknown so lets // take a shot at determining the type. // don't do this for other content-types as you are going to // end up sending text/plain for endpoints that are handled by // asp.net such as .aspx, .asmx, .axd, etc etc contentType = CommonExtensions.GetContentType(_pathTranslated); } value = contentType ?? value; break; } _responseHeadersBuilder.Append(GetKnownResponseHeaderName(index)); _responseHeadersBuilder.Append(": "); _responseHeadersBuilder.Append(value); _responseHeadersBuilder.Append("\r\n"); } public void SetResponseHeader(string name, string value) { _responseHeadersBuilder.Append(name); _responseHeadersBuilder.Append(": "); _responseHeadersBuilder.Append(value); _responseHeadersBuilder.Append("\r\n"); } public override void SendResponseFromFile(string filename, long offset, long length) { if (length == 0) { return; } FileStream f = null; try { f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); SendResponseFromFileStream(f, offset, length); } finally { if (f != null) { f.Close(); } } } public override void SendResponseFromFile(IntPtr handle, long offset, long length) { if (length == 0) { return; } using (var sfh = new SafeFileHandle(handle, false)) { using (var f = new FileStream(sfh, FileAccess.Read)) { SendResponseFromFileStream(f, offset, length); } } } public override void SendResponseFromMemory(byte[] data, int length) { if (length > 0) { var bytes = new byte[length]; Buffer.BlockCopy(data, 0, bytes, 0, length); _responseBodyBytes.Add(bytes); } } public override void SendStatus(int statusCode, string statusDescription) { _responseStatus = statusCode; } public override void SendUnknownResponseHeader(string name, string value) { if (_headersSent) return; _responseHeadersBuilder.Append(name); _responseHeadersBuilder.Append(": "); _responseHeadersBuilder.Append(value); _responseHeadersBuilder.Append("\r\n"); } private bool IsBadPath() { if (_path.IndexOfAny(BadPathChars) >= 0) { return true; } if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(_path, "..", CompareOptions.Ordinal) >= 0) { return true; } if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(_path, "//", CompareOptions.Ordinal) >= 0) { return true; } return false; } private bool IsRequestForRestrictedDirectory() { String p = CultureInfo.InvariantCulture.TextInfo.ToLower(_path); if (_host.VirtualPath != "/") { p = p.Substring(_host.VirtualPath.Length); } foreach (String dir in RestrictedDirs) { if (p.StartsWith(dir, StringComparison.Ordinal)) { if (p.Length == dir.Length || p[dir.Length] == '/') { return true; } } } return false; } private void ParseHeaders() { _knownRequestHeaders = new string[RequestHeaderMaximum]; // construct unknown headers as array list of name1,value1,... var headers = new List<string>(); for (int i = 1; i < _headerByteStrings.Count; i++) { string s = _headerByteStrings[i].GetString(); int c = s.IndexOf(':'); if (c >= 0) { string name = s.Substring(0, c).Trim(); string value = s.Substring(c + 1).Trim(); // remember int knownIndex = GetKnownRequestHeaderIndex(name); if (knownIndex >= 0) { _knownRequestHeaders[knownIndex] = value; } else { headers.Add(name); headers.Add(value); } } } // copy to array unknown headers int n = headers.Count / 2; _unknownRequestHeaders = new string[n][]; int j = 0; for (int i = 0; i < n; i++) { _unknownRequestHeaders[i] = new string[2]; _unknownRequestHeaders[i][0] = headers[j++]; _unknownRequestHeaders[i][1] = headers[j++]; } // remember all raw headers as one string if (_headerByteStrings.Count > 1) { _allRawHeaders = Encoding.UTF8.GetString(_headerBytes, _startHeadersOffset, _endHeadersOffset - _startHeadersOffset); } else { _allRawHeaders = String.Empty; } } private void ParsePostedContent() { _contentLength = 0; _bodyLength = 0; string contentLengthValue = _knownRequestHeaders[HeaderContentLength]; if (contentLengthValue != null) { try { _contentLength = Int32.Parse(contentLengthValue, CultureInfo.InvariantCulture); } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { } } if (_headerBytes.Length > _endHeadersOffset) { _bodyLength = _headerBytes.Length - _endHeadersOffset; if (_bodyLength > _contentLength) { _bodyLength = _contentLength; // don't read more than the content-length } if (_bodyLength > 0) { _body = new byte[_bodyLength]; Buffer.BlockCopy(_headerBytes, _endHeadersOffset, _body, 0, _bodyLength); } } } private void ParseRequestLine() { ByteString requestLine = _headerByteStrings[0]; ByteString[] elems = requestLine.Split(' '); if (elems == null || elems.Length < 2 || elems.Length > 3) { _connection.WriteErrorAndClose(400); return; } _verb = elems[0].GetString(); ByteString urlBytes = elems[1]; _url = urlBytes.GetString(); _protocol = elems.Length == 3 ? elems[2].GetString() : "HTTP/1.0"; // query string int iqs = urlBytes.IndexOf('?'); _queryStringBytes = iqs > 0 ? urlBytes.Substring(iqs + 1).GetBytes() : new byte[0]; iqs = _url.IndexOf('?'); if (_url == "/" && !String.IsNullOrEmpty(_dfPage)) _path = _dfPage; else if (iqs > 0) { _path = _url.Substring(0, iqs); _queryString = _url.Substring(iqs + 1); } else { _path = _url; _queryStringBytes = new byte[0]; } // url-decode path if (_path.IndexOf('%') >= 0) { _path = HttpUtility.UrlDecode(_path, Encoding.UTF8); iqs = _url.IndexOf('?'); if (iqs >= 0) { _url = _path + _url.Substring(iqs); } else { _url = _path; } } // path info int lastDot = _path.LastIndexOf('.'); int lastSlh = _path.LastIndexOf('/'); if (lastDot >= 0 && lastSlh >= 0 && lastDot < lastSlh) { int ipi = _path.IndexOf('/', lastDot); _filePath = _path.Substring(0, ipi); _pathInfo = _path.Substring(ipi); } else { _filePath = _path; _pathInfo = String.Empty; } _pathTranslated = MapPath(_filePath); } private void PrepareResponse() { _headersSent = false; _responseStatus = 200; _responseHeadersBuilder = new StringBuilder(); _responseBodyBytes = new List<byte[]>(); ProcessPlugins(); } private bool ProcessDirectoryListingRequest() { if (_verb != "GET") { return false; } String dirPathTranslated = _pathTranslated; if (_pathInfo.Length > 0) { // directory path can never have pathInfo dirPathTranslated = MapPath(_path); } if (!Directory.Exists(dirPathTranslated)) { return false; } // get all files and subdirs FileSystemInfo[] infos = null; try { infos = (new DirectoryInfo(dirPathTranslated)).GetFileSystemInfos(); } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause { } // determine if parent is appropriate string parentPath = null; if (_path.Length > 1) { int i = _path.LastIndexOf('/', _path.Length - 2); parentPath = (i > 0) ? _path.Substring(0, i) : "/"; if (!_host.IsVirtualPathInApp(parentPath)) { parentPath = null; } } _connection.WriteEntireResponseFromString(200, "Content-type: text/html; charset=utf-8\r\n", Messages.FormatDirectoryListing(_path, parentPath, infos), false); return true; } private bool ProcessDirectoryRequest() { String dirPathTranslated = _pathTranslated; if (_pathInfo.Length > 0) { // directory path can never have pathInfo dirPathTranslated = MapPath(_path); } if (!Directory.Exists(dirPathTranslated)) { return false; } // have to redirect /foo to /foo/ to allow relative links to work if (!_path.EndsWith("/", StringComparison.Ordinal)) { string newPath = _path + "/"; string location = "Location: " + UrlEncodeRedirect(newPath) + "\r\n"; string body = "<html><head><title>Object moved</title></head><body>\r\n" + "<h2>Object moved to <a href='" + newPath + "'>here</a>.</h2>\r\n" + "</body></html>\r\n"; _connection.WriteEntireResponseFromString(302, location, body, false); return true; } // check for the default file foreach (string filename in DefaultFileNames) { string defaultFilePath = dirPathTranslated + "\\" + filename; if (File.Exists(defaultFilePath)) { // pretend the request is for the default file path _path += filename; _filePath = _path; _url = (_queryString != null) ? (_path + "?" + _queryString) : _path; _pathTranslated = defaultFilePath; return false; // go through normal processing } } return false; // go through normal processing } private void ReadAllHeaders() { _headerBytes = null; do { if (!TryReadAllHeaders()) { // something bad happened break; } } while (_endHeadersOffset < 0); // found \r\n\r\n } private void Reset() { _headerBytes = null; _startHeadersOffset = 0; _endHeadersOffset = 0; _headerByteStrings = null; _isClientScriptPath = false; _verb = null; _url = null; _protocol = null; _path = null; _filePath = null; _pathInfo = null; _pathTranslated = null; _queryString = null; _queryStringBytes = null; _contentLength = 0; _bodyLength = 0; _body = null; _allRawHeaders = null; _unknownRequestHeaders = null; _knownRequestHeaders = null; _specialCaseStaticFileHeaders = false; } private void SendResponseFromFileStream(Stream f, long offset, long length) { long fileSize = f.Length; if (length == -1) { length = fileSize - offset; } if (length == 0 || offset < 0 || length > fileSize - offset) { return; } if (offset > 0) { f.Seek(offset, SeekOrigin.Begin); } if (length <= MaxChunkLength) { var fileBytes = new byte[(int)length]; int bytesRead = f.Read(fileBytes, 0, (int)length); SendResponseFromMemory(fileBytes, bytesRead); } else { var chunk = new byte[MaxChunkLength]; var bytesRemaining = (int)length; while (bytesRemaining > 0) { int bytesToRead = (bytesRemaining < MaxChunkLength) ? bytesRemaining : MaxChunkLength; int bytesRead = f.Read(chunk, 0, bytesToRead); SendResponseFromMemory(chunk, bytesRead); bytesRemaining -= bytesRead; // flush to release keep memory if ((bytesRemaining > 0) && (bytesRead > 0)) { FlushResponse(false); } } } } private void SkipAllPostedContent() { if ((_contentLength > 0) && (_bodyLength < _contentLength)) { byte[] buffer; for (int i = _contentLength - _bodyLength; i > 0; i -= buffer.Length) { buffer = _connection.ReadRequestBytes(i); if ((buffer == null) || (buffer.Length == 0)) { return; } } } } /// <summary> /// TODO: defer response until request is written /// </summary> /// <returns></returns> private bool TryParseRequest() { Reset(); ReadAllHeaders(); if (_headerBytes == null || _endHeadersOffset < 0 || _headerByteStrings == null || _headerByteStrings.Count == 0) { _connection.WriteErrorAndClose(400); return false; } ParseRequestLine(); // Check for bad path if (IsBadPath()) { _connection.WriteErrorAndClose(400); return false; } // Check if the path is not well formed or is not for the current app if (!_host.IsVirtualPathInApp(_path, out _isClientScriptPath)) { _connection.WriteErrorAndClose(404); return false; } ParseHeaders(); ParsePostedContent(); return true; } private bool TryReadAllHeaders() { // read the first packet (up to 32K) byte[] headerBytes = _connection.ReadRequestBytes(MaxHeaderBytes); if (headerBytes == null || headerBytes.Length == 0) return false; if (_headerBytes != null) { // previous partial read int len = headerBytes.Length + _headerBytes.Length; if (len > MaxHeaderBytes) return false; var bytes = new byte[len]; Buffer.BlockCopy(_headerBytes, 0, bytes, 0, _headerBytes.Length); Buffer.BlockCopy(headerBytes, 0, bytes, _headerBytes.Length, headerBytes.Length); _headerBytes = bytes; } else { _headerBytes = headerBytes; } // start parsing _startHeadersOffset = -1; _endHeadersOffset = -1; _headerByteStrings = new List<ByteString>(); // find the end of headers var parser = new ByteParser(_headerBytes); for (; ; ) { ByteString line = parser.ReadLine(); if (line == null) { break; } if (_startHeadersOffset < 0) { _startHeadersOffset = parser.CurrentOffset; } if (line.IsEmpty) { _endHeadersOffset = parser.CurrentOffset; break; } _headerByteStrings.Add(line); } return true; } private static string UrlEncodeRedirect(string path) { // this method mimics the logic in HttpResponse.Redirect (which relies on internal methods) // count non-ascii characters byte[] bytes = Encoding.UTF8.GetBytes(path); int count = bytes.Length; int countNonAscii = 0; for (int i = 0; i < count; i++) { if ((bytes[i] & 0x80) != 0) { countNonAscii++; } } // encode all non-ascii characters using UTF-8 %XX if (countNonAscii > 0) { // expand not 'safe' characters into %XX, spaces to +s var expandedBytes = new byte[count + countNonAscii * 2]; int pos = 0; for (int i = 0; i < count; i++) { byte b = bytes[i]; if ((b & 0x80) == 0) { expandedBytes[pos++] = b; } else { expandedBytes[pos++] = (byte)'%'; expandedBytes[pos++] = (byte)IntToHex[(b >> 4) & 0xf]; expandedBytes[pos++] = (byte)IntToHex[b & 0xf]; } } path = Encoding.ASCII.GetString(expandedBytes); } // encode spaces into %20 if (path.IndexOf(' ') >= 0) { path = path.Replace(" ", "%20"); } return path; } private void ProcessPlugins() { if (_connection.Plugins != null) { foreach (string pluginTypeName in _connection.Plugins) { // #TODO: maybe keep plugins instantiated in the connection with reflected method cached? Type pluginType = Type.GetType(pluginTypeName); object plugin = Activator.CreateInstance(pluginType); MethodInfo pluginMethod = plugin.GetType().GetMethod("ProcessRequest"); pluginMethod.Invoke(plugin, new object[] { this }); } } } #region Nested type: ByteParser internal class ByteParser { private readonly byte[] _bytes; private int _pos; public ByteParser(byte[] bytes) { _bytes = bytes; _pos = 0; } public int CurrentOffset { get { return _pos; } } public ByteString ReadLine() { ByteString line = null; for (int i = _pos; i < _bytes.Length; i++) { if (_bytes[i] == (byte)'\n') { int len = i - _pos; if (len > 0 && _bytes[i - 1] == (byte)'\r') { len--; } line = new ByteString(_bytes, _pos, len); _pos = i + 1; return line; } } if (_pos < _bytes.Length) { line = new ByteString(_bytes, _pos, _bytes.Length - _pos); } _pos = _bytes.Length; return line; } } #endregion #region Nested type: ByteString internal class ByteString { private readonly byte[] _bytes; private readonly int _length; private readonly int _offset; public ByteString(byte[] bytes, int offset, int length) { _bytes = bytes; _offset = offset; _length = length; } public byte[] Bytes { get { return _bytes; } } public bool IsEmpty { get { return (_bytes == null || _length == 0); } } public byte this[int index] { get { return _bytes[_offset + index]; } } public int Length { get { return _length; } } public int Offset { get { return _offset; } } public byte[] GetBytes() { var bytes = new byte[_length]; if (_length > 0) Buffer.BlockCopy(_bytes, _offset, bytes, 0, _length); return bytes; } public string GetString(Encoding enc) { if (IsEmpty) return string.Empty; return enc.GetString(_bytes, _offset, _length); } public string GetString() { return GetString(Encoding.UTF8); } public int IndexOf(char ch) { return IndexOf(ch, 0); } public int IndexOf(char ch, int offset) { for (int i = offset; i < _length; i++) { if (this[i] == (byte)ch) return i; } return -1; } public ByteString[] Split(char sep) { var list = new List<ByteString>(); int pos = 0; while (pos < _length) { int i = IndexOf(sep, pos); if (i < 0) { break; } list.Add(Substring(pos, i - pos)); pos = i + 1; while (this[pos] == (byte)sep && pos < _length) { pos++; } } if (pos < _length) list.Add(Substring(pos)); return list.ToArray(); } public ByteString Substring(int offset, int len) { return new ByteString(_bytes, _offset + offset, len); } public ByteString Substring(int offset) { return Substring(offset, _length - offset); } } #endregion } }
// ********************************************************************************** // CassiniDev - http://cassinidev.codeplex.com // // Copyright (c) 2010 Sky Sanders. All rights reserved. // // This source code is subject to terms and conditions of the Microsoft Public // License (Ms-PL). A copy of the license can be found in the license.txt file // included in this distribution. // // You must not remove this notice, or any other, from this software. // // ********************************************************************************** #region using System; #endregion namespace SimpleWebServer { ///<summary> ///</summary> public class RequestEventArgs : EventArgs { private readonly Guid _id; ///<summary> ///</summary> ///<param name="id"></param> ///<param name="requestLog"></param> ///<param name="responseLog"></param> public RequestEventArgs(Guid id) { _id = id; } ///<summary> ///</summary> public Guid Id { get { return _id; } } } }