开发自定义的web IIS服务器 WebDev.WebHost 用控制台托起web服务
上次写了一篇ASP.NET一个简易的WebServer,用控制台程序模拟IIS 托起web服务 看见有一朋友说在中文情况下返回乱码。我平时用的都是英文开发环境,即使涉及到中文也不是乱码,但是在公司中文的vs环境下也出现了乱码。一时半会不中的怎么解决。后来想起vs内嵌的那个服务器。。。。,于是乎拿来改写一下。
先说说几个帮助类吧,我们中的http协议中请求头都是以\r\n\r\n结束的 在请求头中每个指令都是以\r\n分隔的, ByteParser就是用来分隔请求类容,再把一行的内容装到ByteString里面,ByteString主要作用是把字节转为字符。而Messages只是返回一些默认消息。Host就像原先的WebServer一样用来处理请求,Request是实现SimpleWorkerRequest的,用来真正处理用户请求。Server就是用来封装Host的暴露给调用者。至于NtlmAuth类没怎么明白好像是处理身份认证之类的东东。。。
还是吧修改后的代码贴出来吧:
ByteParser.cs
namespace Microsoft.VisualStudio.WebHost { using System; internal sealed class ByteParser { private byte[] _bytes; private int _pos; internal ByteParser(byte[] bytes) { this._bytes = bytes; this._pos = 0; } internal ByteString ReadLine() { ByteString str = null; for (int i = this._pos; i < this._bytes.Length; i++) { if (this._bytes[i] == 10) { int length = i - this._pos; if ((length > 0) && (this._bytes[i - 1] == 13)) { length--; } str = new ByteString(this._bytes, this._pos, length); this._pos = i + 1; return str; } } if (this._pos < this._bytes.Length) { str = new ByteString(this._bytes, this._pos, this._bytes.Length - this._pos); } this._pos = this._bytes.Length; return str; } internal int CurrentOffset { get { return this._pos; } } } }
ByteString.cs
namespace Microsoft.VisualStudio.WebHost { using System; using System.Collections; using System.Reflection; using System.Text; internal sealed class ByteString { private byte[] _bytes; private int _length; private int _offset; public ByteString(byte[] bytes, int offset, int length) { this._bytes = bytes; if (((this._bytes != null) && (offset >= 0)) && ((length >= 0) && ((offset + length) <= this._bytes.Length))) { this._offset = offset; this._length = length; } } public byte[] GetBytes() { byte[] dst = new byte[this._length]; if (this._length > 0) { Buffer.BlockCopy(this._bytes, this._offset, dst, 0, this._length); } return dst; } public string GetString() { return this.GetString(Encoding.UTF8); } public string GetString(Encoding enc) { if (this.IsEmpty) { return string.Empty; } return enc.GetString(this._bytes, this._offset, this._length); } public int IndexOf(char ch) { return this.IndexOf(ch, 0); } public int IndexOf(char ch, int offset) { for (int i = offset; i < this._length; i++) { if (this[i] == ((byte) ch)) { return i; } } return -1; } public ByteString[] Split(char sep) { ArrayList list = new ArrayList(); int offset = 0; while (offset < this._length) { int index = this.IndexOf(sep, offset); if (index < 0) { list.Add(this.Substring(offset)); break; } list.Add(this.Substring(offset, index - offset)); for (offset = index + 1; (offset < this._length) && (this[offset] == ((byte) sep)); offset++) { } } int count = list.Count; ByteString[] strArray = new ByteString[count]; for (int i = 0; i < count; i++) { strArray[i] = (ByteString) list[i]; } return strArray; } public ByteString Substring(int offset) { return this.Substring(offset, this._length - offset); } public ByteString Substring(int offset, int len) { return new ByteString(this._bytes, this._offset + offset, len); } public byte[] Bytes { get { return this._bytes; } } public bool IsEmpty { get { if (this._bytes != null) { return (this._length == 0); } return true; } } public byte this[int index] { get { return this._bytes[this._offset + index]; } } public int Length { get { return this._length; } } public int Offset { get { return this._offset; } } } }
Messages.cs
namespace Microsoft.VisualStudio.WebHost { using System; using System.Globalization; using System.IO; using System.Text; using System.Web; internal class Messages { private const string _dirListingDirFormat = "{0,38:dddd, MMMM dd, yyyy hh:mm tt} <dir> <A href=\"{1}/\">{2}</A>\r\n"; private const string _dirListingFileFormat = "{0,38:dddd, MMMM dd, yyyy hh:mm tt} {1,12:n0} <A href=\"{2}\">{3}</A>\r\n"; private const string _dirListingFormat1 = "<html>\r\n <head>\r\n <title>{0}</title>\r\n"; private const string _dirListingFormat2 = " </head>\r\n <body bgcolor=\"white\">\r\n\r\n <h2> <i>{0}</i> </h2></span>\r\n\r\n <hr width=100% size=1 color=silver>\r\n\r\n<PRE>\r\n"; private const string _dirListingParentFormat = "<A href=\"{0}\">[To Parent Directory]</A>\r\n\r\n"; private static string _dirListingTail = ("</PRE>\r\n <hr width=100% size=1 color=silver>\r\n\r\n <b>{0}:</b> {1} " + VersionString + "\r\n\r\n </font>\r\n\r\n </body>\r\n</html>\r\n"); private const string _httpErrorFormat1 = "<html>\r\n <head>\r\n <title>{0}</title>\r\n"; private static string _httpErrorFormat2 = (" </head>\r\n <body bgcolor=\"white\">\r\n\r\n <span><h1>{0}<hr width=100% size=1 color=silver></h1>\r\n\r\n <h2> <i>{1}</i> </h2></span>\r\n\r\n <hr width=100% size=1 color=silver>\r\n\r\n <b>{2}:</b> {3} " + VersionString + "\r\n\r\n </font>\r\n\r\n </body>\r\n</html>\r\n"); private const string _httpStyle = " <style>\r\n \tbody {font-family:\"Verdana\";font-weight:normal;font-size: 8pt;color:black;} \r\n \tp {font-family:\"Verdana\";font-weight:normal;color:black;margin-top: -5px}\r\n \tb {font-family:\"Verdana\";font-weight:bold;color:black;margin-top: -5px}\r\n \th1 { font-family:\"Verdana\";font-weight:normal;font-size:18pt;color:red }\r\n \th2 { font-family:\"Verdana\";font-weight:normal;font-size:14pt;color:maroon }\r\n \tpre {font-family:\"Lucida Console\";font-size: 8pt}\r\n \t.marker {font-weight: bold; color: black;text-decoration: none;}\r\n \t.version {color: gray;}\r\n \t.error {margin-bottom: 10px;}\r\n \t.expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }\r\n </style>\r\n"; public static string VersionString = GetVersionString(); public static string FormatDirectoryListing(string dirPath, string parentPath, FileSystemInfo[] elements) { StringBuilder builder = new StringBuilder(); string str = string.Format("Directory Listing -- {0}", dirPath ); string str2 = "Version Information"; string str3 = "ASP.NET Development Server"; string str4 = string.Format(CultureInfo.InvariantCulture, _dirListingTail, new object[] { str2, str3 }); builder.Append(string.Format(CultureInfo.InvariantCulture, "<html>\r\n <head>\r\n <title>{0}</title>\r\n", new object[] { str })); builder.Append(" <style>\r\n \tbody {font-family:\"Verdana\";font-weight:normal;font-size: 8pt;color:black;} \r\n \tp {font-family:\"Verdana\";font-weight:normal;color:black;margin-top: -5px}\r\n \tb {font-family:\"Verdana\";font-weight:bold;color:black;margin-top: -5px}\r\n \th1 { font-family:\"Verdana\";font-weight:normal;font-size:18pt;color:red }\r\n \th2 { font-family:\"Verdana\";font-weight:normal;font-size:14pt;color:maroon }\r\n \tpre {font-family:\"Lucida Console\";font-size: 8pt}\r\n \t.marker {font-weight: bold; color: black;text-decoration: none;}\r\n \t.version {color: gray;}\r\n \t.error {margin-bottom: 10px;}\r\n \t.expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }\r\n </style>\r\n"); builder.Append(string.Format(CultureInfo.InvariantCulture, " </head>\r\n <body bgcolor=\"white\">\r\n\r\n <h2> <i>{0}</i> </h2></span>\r\n\r\n <hr width=100% size=1 color=silver>\r\n\r\n<PRE>\r\n", new object[] { str })); if (parentPath != null) { if (!parentPath.EndsWith("/", StringComparison.Ordinal)) { parentPath = parentPath + "/"; } builder.Append(string.Format(CultureInfo.InvariantCulture, "<A href=\"{0}\">[To Parent Directory]</A>\r\n\r\n", new object[] { parentPath })); } if (elements != null) { for (int i = 0; i < elements.Length; i++) { if (elements[i] is FileInfo) { FileInfo info = (FileInfo) elements[i]; builder.Append(string.Format(CultureInfo.InvariantCulture, "{0,38:dddd, MMMM dd, yyyy hh:mm tt} {1,12:n0} <A href=\"{2}\">{3}</A>\r\n", new object[] { info.LastWriteTime, info.Length, info.Name, info.Name })); } else if (elements[i] is DirectoryInfo) { DirectoryInfo info2 = (DirectoryInfo) elements[i]; builder.Append(string.Format(CultureInfo.InvariantCulture, "{0,38:dddd, MMMM dd, yyyy hh:mm tt} <dir> <A href=\"{1}/\">{2}</A>\r\n", new object[] { info2.LastWriteTime, info2.Name, info2.Name })); } } } builder.Append(str4); return builder.ToString(); } public static string FormatErrorMessageBody(int statusCode, string appName) { string statusDescription = HttpWorkerRequest.GetStatusDescription(statusCode); string str2 = string.Format("Server Error in '{0}' Application.", appName); string str3 = string.Format("HTTP Error {0} - {1}.", statusCode, statusDescription); string str4 = "Version Information"; string str5 = "ASP.NET Development Server"; return (string.Format(CultureInfo.InvariantCulture, "<html>\r\n <head>\r\n <title>{0}</title>\r\n", new object[] { statusDescription }) + " <style>\r\n \tbody {font-family:\"Verdana\";font-weight:normal;font-size: 8pt;color:black;} \r\n \tp {font-family:\"Verdana\";font-weight:normal;color:black;margin-top: -5px}\r\n \tb {font-family:\"Verdana\";font-weight:bold;color:black;margin-top: -5px}\r\n \th1 { font-family:\"Verdana\";font-weight:normal;font-size:18pt;color:red }\r\n \th2 { font-family:\"Verdana\";font-weight:normal;font-size:14pt;color:maroon }\r\n \tpre {font-family:\"Lucida Console\";font-size: 8pt}\r\n \t.marker {font-weight: bold; color: black;text-decoration: none;}\r\n \t.version {color: gray;}\r\n \t.error {margin-bottom: 10px;}\r\n \t.expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }\r\n </style>\r\n" + string.Format(CultureInfo.InvariantCulture, _httpErrorFormat2, new object[] { str2, str3, str4, str5 })); } private static string GetVersionString() { return "10.0.0.0"; } } }
NtlmAuth.cs
namespace Microsoft.VisualStudio.WebHost { using System; using System.Runtime.InteropServices; using System.Security; using System.Security.Principal; [SuppressUnmanagedCodeSecurity] internal sealed class NtlmAuth : IDisposable { private string _blob; private bool _completed; private SecHandle _credentialsHandle; private bool _credentialsHandleAcquired; private SecBuffer _inputBuffer; private SecBufferDesc _inputBufferDesc; private SecBuffer _outputBuffer; private SecBufferDesc _outputBufferDesc; private SecHandle _securityContext; private bool _securityContextAcquired; private uint _securityContextAttributes; private SecurityIdentifier _sid; private long _timestamp; private const int ISC_REQ_ALLOCATE_MEMORY = 0x100; private const int ISC_REQ_CONFIDENTIALITY = 0x10; private const int ISC_REQ_DELEGATE = 1; private const int ISC_REQ_MUTUAL_AUTH = 2; private const int ISC_REQ_PROMPT_FOR_CREDS = 0x40; private const int ISC_REQ_REPLAY_DETECT = 4; private const int ISC_REQ_SEQUENCE_DETECT = 8; private const int ISC_REQ_STANDARD_FLAGS = 20; private const int ISC_REQ_USE_SESSION_KEY = 0x20; private const int ISC_REQ_USE_SUPPLIED_CREDS = 0x80; private const int SEC_E_OK = 0; private const int SEC_I_COMPLETE_AND_CONTINUE = 0x90314; private const int SEC_I_COMPLETE_NEEDED = 0x90313; private const int SEC_I_CONTINUE_NEEDED = 0x90312; private const int SECBUFFER_DATA = 1; private const int SECBUFFER_EMPTY = 0; private const int SECBUFFER_TOKEN = 2; private const int SECBUFFER_VERSION = 0; private const int SECPKG_CRED_INBOUND = 1; private const int SECURITY_NETWORK_DREP = 0; public NtlmAuth() { if (AcquireCredentialsHandle(null, "NTLM", 1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref this._credentialsHandle, ref this._timestamp) != 0) { throw new InvalidOperationException(); } this._credentialsHandleAcquired = true; } [DllImport("SECUR32.DLL", CharSet=CharSet.Unicode)] private 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)] private static extern int AcquireCredentialsHandle(string pszPrincipal, string pszPackage, uint fCredentialUse, IntPtr pvLogonID, IntPtr pAuthData, IntPtr pGetKeyFn, IntPtr pvGetKeyArgument, ref SecHandle phCredential, ref long ptsExpiry); public unsafe bool Authenticate(string blobString) { this._blob = null; byte[] buffer = Convert.FromBase64String(blobString); byte[] inArray = new byte[0x4000]; fixed (SecHandle* voidRef = &this._securityContext) { fixed (SecBuffer* voidRef2 = &this._inputBuffer) { fixed (SecBuffer* voidRef3 = &this._outputBuffer) { fixed (void* voidRef4 = buffer) { fixed (void* voidRef5 = inArray) { IntPtr zero = IntPtr.Zero; if (this._securityContextAcquired) { zero = (IntPtr)voidRef; } this._inputBufferDesc.ulVersion = 0; this._inputBufferDesc.cBuffers = 1; this._inputBufferDesc.pBuffers = (IntPtr)voidRef2; this._inputBuffer.cbBuffer = (uint)buffer.Length; this._inputBuffer.BufferType = 2; this._inputBuffer.pvBuffer = (IntPtr)voidRef4; this._outputBufferDesc.ulVersion = 0; this._outputBufferDesc.cBuffers = 1; this._outputBufferDesc.pBuffers = (IntPtr)voidRef3; this._outputBuffer.cbBuffer = (uint)inArray.Length; this._outputBuffer.BufferType = 2; this._outputBuffer.pvBuffer = (IntPtr)voidRef5; int num = AcceptSecurityContext(ref this._credentialsHandle, zero, ref this._inputBufferDesc, 20, 0, ref this._securityContext, ref this._outputBufferDesc, ref this._securityContextAttributes, ref this._timestamp); if (num == 0x90312) { this._securityContextAcquired = true; this._blob = Convert.ToBase64String(inArray, 0, (int)this._outputBuffer.cbBuffer); } else { if (num != 0) { return false; } IntPtr phToken = IntPtr.Zero; if (QuerySecurityContextToken(ref this._securityContext, ref phToken) != 0) { return false; } try { using (WindowsIdentity identity = new WindowsIdentity(phToken)) { this._sid = identity.User; } } finally { CloseHandle(phToken); } this._completed = true; } } } } } } return true; } [DllImport("KERNEL32.DLL", CharSet=CharSet.Unicode)] private static extern int CloseHandle(IntPtr phToken); [DllImport("SECUR32.DLL", CharSet=CharSet.Unicode)] private static extern int DeleteSecurityContext(ref SecHandle phContext); ~NtlmAuth() { this.FreeUnmanagedResources(); } [DllImport("SECUR32.DLL", CharSet=CharSet.Unicode)] private static extern int FreeCredentialsHandle(ref SecHandle phCredential); private void FreeUnmanagedResources() { if (this._securityContextAcquired) { DeleteSecurityContext(ref this._securityContext); } if (this._credentialsHandleAcquired) { FreeCredentialsHandle(ref this._credentialsHandle); } } [DllImport("SECUR32.DLL", CharSet=CharSet.Unicode)] private static extern int QuerySecurityContextToken(ref SecHandle phContext, ref IntPtr phToken); void IDisposable.Dispose() { this.FreeUnmanagedResources(); GC.SuppressFinalize(this); } public string Blob { get { return this._blob; } } public bool Completed { get { return this._completed; } } public SecurityIdentifier SID { get { return this._sid; } } [StructLayout(LayoutKind.Sequential)] private struct SecBuffer { public uint cbBuffer; public uint BufferType; public IntPtr pvBuffer; } [StructLayout(LayoutKind.Sequential)] private struct SecBufferDesc { public uint ulVersion; public uint cBuffers; public IntPtr pBuffers; } [StructLayout(LayoutKind.Sequential)] private struct SecHandle { public IntPtr dwLower; public IntPtr dwUpper; } } }
Host.cs
namespace Microsoft.VisualStudio.WebHost { using System; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Security.Principal; using System.Threading; using System.Web; using System.Web.Hosting; internal sealed class Host : MarshalByRefObject, IRegisteredObject { private bool _disableDirectoryListing; private string _installPath; private string _lowerCasedClientScriptPathWithTrailingSlash; private string _lowerCasedVirtualPath; private string _lowerCasedVirtualPathWithTrailingSlash; //private volatile int _pendingCallsCount; private int _pendingCallsCount; private string _physicalClientScriptPath; private string _physicalPath; private int _port; private bool _requireAuthentication; private Server _server; private string _virtualPath; public Host() { HostingEnvironment.RegisterObject(this); } private void AddPendingCall() { Interlocked.Increment(ref this._pendingCallsCount); } public void Configure(Server server, int port, string virtualPath, string physicalPath, bool requireAuthentication) { this.Configure(server, port, virtualPath, physicalPath, requireAuthentication, false); } public void Configure(Server server, int port, string virtualPath, string physicalPath, bool requireAuthentication, bool disableDirectoryListing) { this._server = server; this._port = port; this._installPath = null; this._virtualPath = virtualPath; this._requireAuthentication = requireAuthentication; this._disableDirectoryListing = disableDirectoryListing; this._lowerCasedVirtualPath = CultureInfo.InvariantCulture.TextInfo.ToLower(this._virtualPath); this._lowerCasedVirtualPathWithTrailingSlash = virtualPath.EndsWith("/", StringComparison.Ordinal) ? virtualPath : (virtualPath + "/"); this._lowerCasedVirtualPathWithTrailingSlash = CultureInfo.InvariantCulture.TextInfo.ToLower(this._lowerCasedVirtualPathWithTrailingSlash); this._physicalPath = physicalPath; this._physicalClientScriptPath = HttpRuntime.AspClientScriptPhysicalPath + @"\"; this._lowerCasedClientScriptPathWithTrailingSlash = CultureInfo.InvariantCulture.TextInfo.ToLower(HttpRuntime.AspClientScriptVirtualPath + "/"); } public SecurityIdentifier GetProcessSID() { using (WindowsIdentity identity = new WindowsIdentity(this._server.GetProcessToken())) { return identity.User; } } public IntPtr GetProcessToken() { new SecurityPermission(PermissionState.Unrestricted).Assert(); return this._server.GetProcessToken(); } public string GetProcessUser() { return this._server.GetProcessUser(); } public override object InitializeLifetimeService() { return null; } public bool IsVirtualPathAppPath(string path) { if (path == null) { return false; } path = CultureInfo.InvariantCulture.TextInfo.ToLower(path); if (!(path == this._lowerCasedVirtualPath)) { return (path == this._lowerCasedVirtualPathWithTrailingSlash); } return true; } public bool IsVirtualPathInApp(string path) { bool flag; return this.IsVirtualPathInApp(path, out flag); } public bool IsVirtualPathInApp(string path, out bool isClientScriptPath) { isClientScriptPath = false; if (path != null) { path = CultureInfo.InvariantCulture.TextInfo.ToLower(path); if ((this._virtualPath == "/") && path.StartsWith("/", StringComparison.Ordinal)) { if (path.StartsWith(this._lowerCasedClientScriptPathWithTrailingSlash, StringComparison.Ordinal)) { isClientScriptPath = true; } return true; } if (path.StartsWith(this._lowerCasedVirtualPathWithTrailingSlash, StringComparison.Ordinal)) { return true; } if (path == this._lowerCasedVirtualPath) { return true; } if (path.StartsWith(this._lowerCasedClientScriptPathWithTrailingSlash, StringComparison.Ordinal)) { isClientScriptPath = true; return true; } } return false; } public void ProcessRequest(Connection conn) { this.AddPendingCall(); try { new Request(this, conn).Process(); } finally { this.RemovePendingCall(); } } private void RemovePendingCall() { Interlocked.Decrement(ref this._pendingCallsCount); } [SecurityPermission(SecurityAction.Assert, Unrestricted=true)] public void Shutdown() { HostingEnvironment.InitiateShutdown(); } void IRegisteredObject.Stop(bool immediate) { if (this._server != null) { this._server.HostStopped(); } this.WaitForPendingCallsToFinish(); HostingEnvironment.UnregisterObject(this); } private void WaitForPendingCallsToFinish() { while (this._pendingCallsCount > 0) { Thread.Sleep(250); } } public bool DisableDirectoryListing { get { return this._disableDirectoryListing; } } public string InstallPath { get { return this._installPath; } } public string NormalizedClientScriptPath { get { return this._lowerCasedClientScriptPathWithTrailingSlash; } } public string NormalizedVirtualPath { get { return this._lowerCasedVirtualPathWithTrailingSlash; } } public string PhysicalClientScriptPath { get { return this._physicalClientScriptPath; } } public string PhysicalPath { get { return this._physicalPath; } } public int Port { get { return this._port; } } public bool RequireAuthentication { get { return this._requireAuthentication; } } public string VirtualPath { get { return this._virtualPath; } } } }
Connection.cs
namespace Microsoft.VisualStudio.WebHost { using System; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; using System.Web; internal sealed class Connection : MarshalByRefObject { private static string _defaultLoalhostIP; private static string _localServerIP; private Server _server; private Socket _socket; internal Connection(Server server, Socket socket) { this._server = server; this._socket = socket; } internal void Close() { try { this._socket.Shutdown(SocketShutdown.Both); this._socket.Close(); } catch { } finally { this._socket = null; } } private string GetErrorResponseBody(int statusCode, string message) { string str = Messages.FormatErrorMessageBody(statusCode, this._server.VirtualPath); if ((message != null) && (message.Length > 0)) { str = str + "\r\n<!--\r\n" + message + "\r\n-->"; } return str; } public override object InitializeLifetimeService() { return null; } private static string MakeContentTypeHeader(string fileName) { string str = null; FileInfo info = new FileInfo(fileName); switch (info.Extension.ToLowerInvariant()) { case ".bmp": str = "image/bmp"; break; case ".css": str = "text/css"; break; case ".gif": str = "image/gif"; break; case ".ico": str = "image/x-icon"; break; case ".htm": case ".html": str = "text/html"; break; case ".jpe": case ".jpeg": case ".jpg": str = "image/jpeg"; break; case ".js": str = "application/x-javascript"; break; } if (str == null) { return null; } return ("Content-Type: " + str + "\r\n"); } private static string MakeResponseHeaders(int statusCode, string moreHeaders, int contentLength, bool keepAlive) { StringBuilder builder = new StringBuilder(); builder.Append(string.Concat(new object[] { "HTTP/1.1 ", statusCode, " ", HttpWorkerRequest.GetStatusDescription(statusCode), "\r\n" })); builder.Append("Server: ASP.NET Development Server/" + Messages.VersionString + "\r\n"); builder.Append("Date: " + DateTime.Now.ToUniversalTime().ToString("R", DateTimeFormatInfo.InvariantInfo) + "\r\n"); if (contentLength >= 0) { builder.Append("Content-Length: " + contentLength + "\r\n"); } if (moreHeaders != null) { builder.Append(moreHeaders); } if (!keepAlive) { builder.Append("Connection: Close\r\n"); } builder.Append("\r\n"); return builder.ToString(); } internal byte[] ReadRequestBytes(int maxBytes) { try { if (this.WaitForRequestBytes() == 0) { return null; } int available = this._socket.Available; if (available > maxBytes) { available = maxBytes; } int count = 0; byte[] buffer = new byte[available]; if (available > 0) { count = this._socket.Receive(buffer, 0, available, SocketFlags.None); } if (count < available) { byte[] dst = new byte[count]; if (count > 0) { Buffer.BlockCopy(buffer, 0, dst, 0, count); } buffer = dst; } return buffer; } catch { return null; } } internal int WaitForRequestBytes() { int available = 0; try { if (this._socket.Available == 0) { this._socket.Poll(0x186a0, SelectMode.SelectRead); if ((this._socket.Available == 0) && this._socket.Connected) { this._socket.Poll(0x1c9c380, SelectMode.SelectRead); } } available = this._socket.Available; } catch { } return available; } internal void Write100Continue() { this.WriteEntireResponseFromString(100, null, null, true); } internal void WriteBody(byte[] data, int offset, int length) { try { this._socket.Send(data, offset, length, SocketFlags.None); } catch (SocketException) { } } internal void WriteEntireResponseFromFile(string fileName, bool keepAlive) { if (!System.IO.File.Exists(fileName)) { this.WriteErrorAndClose(0x194); } else { string moreHeaders = MakeContentTypeHeader(fileName); if (moreHeaders == null) { this.WriteErrorAndClose(0x193); } else { bool flag = false; FileStream stream = null; try { stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); int length = (int) stream.Length; byte[] buffer = new byte[length]; int contentLength = stream.Read(buffer, 0, length); string s = MakeResponseHeaders(200, moreHeaders, contentLength, keepAlive); this._socket.Send(Encoding.UTF8.GetBytes(s)); this._socket.Send(buffer, 0, contentLength, SocketFlags.None); flag = true; } catch (SocketException) { } finally { if (!keepAlive || !flag) { this.Close(); } if (stream != null) { stream.Close(); } } } } } internal void WriteEntireResponseFromString(int statusCode, string extraHeaders, string body, bool keepAlive) { try { int contentLength = (body != null) ? Encoding.UTF8.GetByteCount(body) : 0; string str = MakeResponseHeaders(statusCode, extraHeaders, contentLength, keepAlive); this._socket.Send(Encoding.UTF8.GetBytes(str + body)); } catch (SocketException) { } finally { if (!keepAlive) { this.Close(); } } } internal void WriteErrorAndClose(int statusCode) { this.WriteErrorAndClose(statusCode, null); } internal void WriteErrorAndClose(int statusCode, string message) { this.WriteEntireResponseFromString(statusCode, "Content-type:text/html;charset=utf-8\r\n", this.GetErrorResponseBody(statusCode, message), false); } internal void WriteErrorWithExtraHeadersAndKeepAlive(int statusCode, string extraHeaders) { this.WriteEntireResponseFromString(statusCode, extraHeaders, this.GetErrorResponseBody(statusCode, null), true); } internal void WriteHeaders(int statusCode, string extraHeaders) { string s = MakeResponseHeaders(statusCode, extraHeaders, -1, false); try { this._socket.Send(Encoding.UTF8.GetBytes(s)); } catch (SocketException) { } } internal bool Connected { get { return this._socket.Connected; } } private string DefaultLocalHostIP { get { if (string.IsNullOrEmpty(_defaultLoalhostIP)) { if (!Socket.OSSupportsIPv4 && Socket.OSSupportsIPv6) { _defaultLoalhostIP = "::1"; } else { _defaultLoalhostIP = "127.0.0.1"; } } return _defaultLoalhostIP; } } internal bool IsLocal { get { string remoteIP = this.RemoteIP; if (string.IsNullOrEmpty(remoteIP)) { return false; } if ((!remoteIP.Equals("127.0.0.1") && !remoteIP.Equals("::1")) && !remoteIP.Equals("::ffff:127.0.0.1")) { return LocalServerIP.Equals(remoteIP); } return true; } } internal string LocalIP { get { IPEndPoint localEndPoint = (IPEndPoint) this._socket.LocalEndPoint; if ((localEndPoint != null) && (localEndPoint.Address != null)) { return localEndPoint.Address.ToString(); } return this.DefaultLocalHostIP; } } private static string LocalServerIP { get { if (_localServerIP == null) { _localServerIP = Dns.GetHostEntry(Environment.MachineName).AddressList[0].ToString(); } return _localServerIP; } } internal string RemoteIP { get { IPEndPoint remoteEndPoint = (IPEndPoint) this._socket.RemoteEndPoint; if ((remoteEndPoint != null) && (remoteEndPoint.Address != null)) { return remoteEndPoint.Address.ToString(); } return ""; } } } }
Request.cs
namespace Microsoft.VisualStudio.WebHost { using Microsoft.Win32.SafeHandles; using System; using System.Collections; using System.Globalization; using System.IO; using System.Security; using System.Security.Permissions; using System.Text; using System.Web; using System.Web.Hosting; internal sealed class Request : SimpleWorkerRequest { private string _allRawHeaders; private Connection _connection; private IStackWalk _connectionPermission; private int _contentLength; private int _endHeadersOffset; private string _filePath; private byte[] _headerBytes; private ArrayList _headerByteStrings; private bool _headersSent; private Host _host; private bool _isClientScriptPath; private string[] _knownRequestHeaders; private string _path; private string _pathInfo; private string _pathTranslated; private byte[] _preloadedContent; private int _preloadedContentLength; private string _prot; private string _queryString; private byte[] _queryStringBytes; private ArrayList _responseBodyBytes; private StringBuilder _responseHeadersBuilder; private int _responseStatus; private bool _specialCaseStaticFileHeaders; private int _startHeadersOffset; private string[][] _unknownRequestHeaders; private string _url; private string _verb; private static char[] badPathChars = new char[] { '%', '>', '<', ':', '\\' }; private static string[] defaultFileNames = new string[] { "default.aspx", "default.htm", "default.html" }; private static char[] IntToHex = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private const int MaxChunkLength = 0x10000; private const int maxHeaderBytes = 0x8000; private static string[] restrictedDirs = new string[] { "/bin", "/app_browsers", "/app_code", "/app_data", "/app_localresources", "/app_globalresources", "/app_webreferences" }; public Request(Host host, Connection connection) : base(string.Empty, string.Empty, null) { this._connectionPermission = new PermissionSet(PermissionState.Unrestricted); this._host = host; this._connection = connection; } public override void CloseConnection() { this._connectionPermission.Assert(); this._connection.Close(); } public override void EndOfRequest() { } public override void FlushResponse(bool finalFlush) { if ((((this._responseStatus != 0x194) || this._headersSent) || (!finalFlush || (this._verb != "GET"))) || !this.ProcessDirectoryListingRequest()) { this._connectionPermission.Assert(); if (!this._headersSent) { this._connection.WriteHeaders(this._responseStatus, this._responseHeadersBuilder.ToString()); this._headersSent = true; } for (int i = 0; i < this._responseBodyBytes.Count; i++) { byte[] data = (byte[]) this._responseBodyBytes[i]; this._connection.WriteBody(data, 0, data.Length); } this._responseBodyBytes = new ArrayList(); if (finalFlush) { this._connection.Close(); } } } public override string GetAppPath() { return this._host.VirtualPath; } public override string GetAppPathTranslated() { return this._host.PhysicalPath; } public override string GetFilePath() { return this._filePath; } public override string GetFilePathTranslated() { return this._pathTranslated; } public override string GetHttpVerbName() { return this._verb; } public override string GetHttpVersion() { return this._prot; } public override string GetKnownRequestHeader(int index) { return this._knownRequestHeaders[index]; } public override string GetLocalAddress() { this._connectionPermission.Assert(); return this._connection.LocalIP; } public override int GetLocalPort() { return this._host.Port; } public override string GetPathInfo() { return this._pathInfo; } public override byte[] GetPreloadedEntityBody() { return this._preloadedContent; } public override string GetQueryString() { return this._queryString; } public override byte[] GetQueryStringRawBytes() { return this._queryStringBytes; } public override string GetRawUrl() { return this._url; } public override string GetRemoteAddress() { this._connectionPermission.Assert(); return this._connection.RemoteIP; } public override int GetRemotePort() { return 0; } public override string GetServerName() { string localAddress = this.GetLocalAddress(); if ((!localAddress.Equals("127.0.0.1") && !localAddress.Equals("::1")) && !localAddress.Equals("::ffff:127.0.0.1")) { return localAddress; } return "localhost"; } 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 (this.GetUserToken() != IntPtr.Zero) { processUser = this._host.GetProcessUser(); } return processUser; } if ((str2 == "AUTH_TYPE") && (this.GetUserToken() != IntPtr.Zero)) { processUser = "NTLM"; } return processUser; } } else { return this._allRawHeaders; } return this._prot; } public override string GetUnknownRequestHeader(string name) { int length = this._unknownRequestHeaders.Length; for (int i = 0; i < length; i++) { if (string.Compare(name, this._unknownRequestHeaders[i][0], StringComparison.OrdinalIgnoreCase) == 0) { return this._unknownRequestHeaders[i][1]; } } return null; } public override string[][] GetUnknownRequestHeaders() { return this._unknownRequestHeaders; } public override string GetUriPath() { return this._path; } public override IntPtr GetUserToken() { return this._host.GetProcessToken(); } public override bool HeadersSent() { return this._headersSent; } private bool IsBadPath() { return ((this._path.IndexOfAny(badPathChars) >= 0) || ((CultureInfo.InvariantCulture.CompareInfo.IndexOf(this._path, "..", CompareOptions.Ordinal) >= 0) || (CultureInfo.InvariantCulture.CompareInfo.IndexOf(this._path, "//", CompareOptions.Ordinal) >= 0))); } public override bool IsClientConnected() { this._connectionPermission.Assert(); return this._connection.Connected; } public override bool IsEntireEntityBodyIsPreloaded() { return (this._contentLength == this._preloadedContentLength); } private bool IsRequestForRestrictedDirectory() { string str = CultureInfo.InvariantCulture.TextInfo.ToLower(this._path); if (this._host.VirtualPath != "/") { str = str.Substring(this._host.VirtualPath.Length); } foreach (string str2 in restrictedDirs) { if (str.StartsWith(str2, StringComparison.Ordinal) && ((str.Length == str2.Length) || (str[str2.Length] == '/'))) { return true; } } return false; } public override string MapPath(string path) { string physicalPath = string.Empty; bool isClientScriptPath = false; if (((path == null) || (path.Length == 0)) || path.Equals("/")) { if (this._host.VirtualPath == "/") { physicalPath = this._host.PhysicalPath; } else { physicalPath = Environment.SystemDirectory; } } else if (this._host.IsVirtualPathAppPath(path)) { physicalPath = this._host.PhysicalPath; } else if (this._host.IsVirtualPathInApp(path, out isClientScriptPath)) { if (isClientScriptPath) { physicalPath = this._host.PhysicalClientScriptPath + path.Substring(this._host.NormalizedClientScriptPath.Length); } else { physicalPath = this._host.PhysicalPath + path.Substring(this._host.NormalizedVirtualPath.Length); } } else if (path.StartsWith("/", StringComparison.Ordinal)) { physicalPath = this._host.PhysicalPath + path.Substring(1); } else { physicalPath = this._host.PhysicalPath + path; } physicalPath = physicalPath.Replace('/', '\\'); if (physicalPath.EndsWith(@"\", StringComparison.Ordinal) && !physicalPath.EndsWith(@":\", StringComparison.Ordinal)) { physicalPath = physicalPath.Substring(0, physicalPath.Length - 1); } return physicalPath; } private void ParseHeaders() { this._knownRequestHeaders = new string[40]; ArrayList list = new ArrayList(); for (int i = 1; i < this._headerByteStrings.Count; i++) { string str = ((ByteString) this._headerByteStrings[i]).GetString(); int index = str.IndexOf(':'); if (index >= 0) { string header = str.Substring(0, index).Trim(); string str3 = str.Substring(index + 1).Trim(); int knownRequestHeaderIndex = HttpWorkerRequest.GetKnownRequestHeaderIndex(header); if (knownRequestHeaderIndex >= 0) { this._knownRequestHeaders[knownRequestHeaderIndex] = str3; } else { list.Add(header); list.Add(str3); } } } int num4 = list.Count / 2; this._unknownRequestHeaders = new string[num4][]; int num5 = 0; for (int j = 0; j < num4; j++) { this._unknownRequestHeaders[j] = new string[] { (string) list[num5++], (string) list[num5++] }; } if (this._headerByteStrings.Count > 1) { this._allRawHeaders = Encoding.UTF8.GetString(this._headerBytes, this._startHeadersOffset, this._endHeadersOffset - this._startHeadersOffset); } else { this._allRawHeaders = string.Empty; } } private void ParsePostedContent() { this._contentLength = 0; this._preloadedContentLength = 0; string s = this._knownRequestHeaders[11]; if (s != null) { try { this._contentLength = int.Parse(s, CultureInfo.InvariantCulture); } catch { } } if (this._headerBytes.Length > this._endHeadersOffset) { this._preloadedContentLength = this._headerBytes.Length - this._endHeadersOffset; if (this._preloadedContentLength > this._contentLength) { this._preloadedContentLength = this._contentLength; } if (this._preloadedContentLength > 0) { this._preloadedContent = new byte[this._preloadedContentLength]; Buffer.BlockCopy(this._headerBytes, this._endHeadersOffset, this._preloadedContent, 0, this._preloadedContentLength); } } } private void ParseRequestLine() { ByteString[] strArray = ((ByteString) this._headerByteStrings[0]).Split(' '); if (((strArray == null) || (strArray.Length < 2)) || (strArray.Length > 3)) { this._connection.WriteErrorAndClose(400); } else { this._verb = strArray[0].GetString(); ByteString str2 = strArray[1]; this._url = str2.GetString(); if (this._url.IndexOf((char)0xfffd) >= 0) { this._url = str2.GetString(Encoding.Default); } if (strArray.Length == 3) { this._prot = strArray[2].GetString(); } else { this._prot = "HTTP/1.0"; } int index = str2.IndexOf('?'); if (index > 0) { this._queryStringBytes = str2.Substring(index + 1).GetBytes(); } else { this._queryStringBytes = new byte[0]; } index = this._url.IndexOf('?'); if (index > 0) { this._path = this._url.Substring(0, index); this._queryString = this._url.Substring(index + 1); } else { this._path = this._url; this._queryString = string.Empty; } if (this._path.IndexOf('%') >= 0) { this._path = HttpUtility.UrlDecode(this._path, Encoding.UTF8); index = this._url.IndexOf('?'); if (index >= 0) { this._url = this._path + this._url.Substring(index); } else { this._url = this._path; } } int startIndex = this._path.LastIndexOf('.'); int num3 = this._path.LastIndexOf('/'); if (((startIndex >= 0) && (num3 >= 0)) && (startIndex < num3)) { int length = this._path.IndexOf('/', startIndex); this._filePath = this._path.Substring(0, length); this._pathInfo = this._path.Substring(length); } else { this._filePath = this._path; this._pathInfo = string.Empty; } this._pathTranslated = this.MapPath(this._filePath); } } private void PrepareResponse() { this._headersSent = false; this._responseStatus = 200; this._responseHeadersBuilder = new StringBuilder(); this._responseBodyBytes = new ArrayList(); } [AspNetHostingPermission(SecurityAction.Assert, Level=AspNetHostingPermissionLevel.Medium)] public void Process() { if (this.TryParseRequest()) { if (((this._verb == "POST") && (this._contentLength > 0)) && (this._preloadedContentLength < this._contentLength)) { this._connection.Write100Continue(); } if (!this._host.RequireAuthentication || this.TryNtlmAuthenticate()) { if (this._isClientScriptPath) { this._connection.WriteEntireResponseFromFile(this._host.PhysicalClientScriptPath + this._path.Substring(this._host.NormalizedClientScriptPath.Length), false); } else if (this.IsRequestForRestrictedDirectory()) { this._connection.WriteErrorAndClose(0x193); } else if (!this.ProcessDefaultDocumentRequest()) { this.PrepareResponse(); HttpRuntime.ProcessRequest(this); } } } } private bool ProcessDefaultDocumentRequest() { if (this._verb == "GET") { string path = this._pathTranslated; if (this._pathInfo.Length > 0) { path = this.MapPath(this._path); } if (!Directory.Exists(path)) { return false; } if (!this._path.EndsWith("/", StringComparison.Ordinal)) { string str2 = this._path + "/"; string extraHeaders = "Location: " + UrlEncodeRedirect(str2) + "\r\n"; string body = "<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved to <a href='" + str2 + "'>here</a>.</h2>\r\n</body></html>\r\n"; this._connection.WriteEntireResponseFromString(0x12e, extraHeaders, body, false); return true; } foreach (string str5 in defaultFileNames) { string str6 = path + @"\" + str5; if (File.Exists(str6)) { this._path = this._path + str5; this._filePath = this._path; this._url = (this._queryString != null) ? (this._path + "?" + this._queryString) : this._path; this._pathTranslated = str6; return false; } } } return false; } private bool ProcessDirectoryListingRequest() { if (this._verb != "GET") { return false; } string path = this._pathTranslated; if (this._pathInfo.Length > 0) { path = this.MapPath(this._path); } if (!Directory.Exists(path)) { return false; } if (this._host.DisableDirectoryListing) { return false; } FileSystemInfo[] elements = null; try { elements = new DirectoryInfo(path).GetFileSystemInfos(); } catch { } string str2 = null; if (this._path.Length > 1) { int length = this._path.LastIndexOf('/', this._path.Length - 2); str2 = (length > 0) ? this._path.Substring(0, length) : "/"; if (!this._host.IsVirtualPathInApp(str2)) { str2 = null; } } this._connection.WriteEntireResponseFromString(200, "Content-type: text/html; charset=utf-8\r\n", Messages.FormatDirectoryListing(this._path, str2, elements), false); return true; } private void ReadAllHeaders() { this._headerBytes = null; do { if (!this.TryReadAllHeaders()) { return; } } while (this._endHeadersOffset < 0); } public override int ReadEntityBody(byte[] buffer, int size) { int count = 0; this._connectionPermission.Assert(); byte[] src = this._connection.ReadRequestBytes(size); if ((src != null) && (src.Length > 0)) { count = src.Length; Buffer.BlockCopy(src, 0, buffer, 0, count); } return count; } private void Reset() { this._headerBytes = null; this._startHeadersOffset = 0; this._endHeadersOffset = 0; this._headerByteStrings = null; this._isClientScriptPath = false; this._verb = null; this._url = null; this._prot = null; this._path = null; this._filePath = null; this._pathInfo = null; this._pathTranslated = null; this._queryString = null; this._queryStringBytes = null; this._contentLength = 0; this._preloadedContentLength = 0; this._preloadedContent = null; this._allRawHeaders = null; this._unknownRequestHeaders = null; this._knownRequestHeaders = null; this._specialCaseStaticFileHeaders = false; } public override void SendCalculatedContentLength(int contentLength) { if (!this._headersSent) { this._responseHeadersBuilder.Append("Content-Length: "); this._responseHeadersBuilder.Append(contentLength.ToString(CultureInfo.InvariantCulture)); this._responseHeadersBuilder.Append("\r\n"); } } public override void SendKnownResponseHeader(int index, string value) { if (!this._headersSent) { switch (index) { case 1: case 2: case 0x1a: return; case 0x12: case 0x13: if (!this._specialCaseStaticFileHeaders) { break; } return; case 20: if (!(value == "bytes")) { break; } this._specialCaseStaticFileHeaders = true; return; } this._responseHeadersBuilder.Append(HttpWorkerRequest.GetKnownResponseHeaderName(index)); this._responseHeadersBuilder.Append(": "); this._responseHeadersBuilder.Append(value); this._responseHeadersBuilder.Append("\r\n"); } } public override void SendResponseFromFile(IntPtr handle, long offset, long length) { if (length != 0) { FileStream f = null; try { SafeFileHandle handle2 = new SafeFileHandle(handle, false); f = new FileStream(handle2, FileAccess.Read); this.SendResponseFromFileStream(f, offset, length); } finally { if (f != null) { f.Close(); f = null; } } } } public override void SendResponseFromFile(string filename, long offset, long length) { if (length != 0) { FileStream f = null; try { f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); this.SendResponseFromFileStream(f, offset, length); } finally { if (f != null) { f.Close(); } } } } private void SendResponseFromFileStream(FileStream f, long offset, long length) { long num = f.Length; if (length == -1) { length = num - offset; } if (((length != 0) && (offset >= 0)) && (length <= (num - offset))) { if (offset > 0) { f.Seek(offset, SeekOrigin.Begin); } if (length <= 0x10000) { byte[] buffer = new byte[(int) length]; int num2 = f.Read(buffer, 0, (int) length); this.SendResponseFromMemory(buffer, num2); } else { byte[] buffer2 = new byte[0x10000]; int num3 = (int) length; while (num3 > 0) { int count = (num3 < 0x10000) ? num3 : 0x10000; int num5 = f.Read(buffer2, 0, count); this.SendResponseFromMemory(buffer2, num5); num3 -= num5; if ((num3 > 0) && (num5 > 0)) { this.FlushResponse(false); } } } } } public override void SendResponseFromMemory(byte[] data, int length) { if (length > 0) { byte[] dst = new byte[length]; Buffer.BlockCopy(data, 0, dst, 0, length); this._responseBodyBytes.Add(dst); } } public override void SendStatus(int statusCode, string statusDescription) { this._responseStatus = statusCode; } public override void SendUnknownResponseHeader(string name, string value) { if (!this._headersSent) { this._responseHeadersBuilder.Append(name); this._responseHeadersBuilder.Append(": "); this._responseHeadersBuilder.Append(value); this._responseHeadersBuilder.Append("\r\n"); } } private void SkipAllPostedContent() { if ((this._contentLength > 0) && (this._preloadedContentLength < this._contentLength)) { byte[] buffer; for (int i = this._contentLength - this._preloadedContentLength; i > 0; i -= buffer.Length) { buffer = this._connection.ReadRequestBytes(i); if ((buffer == null) || (buffer.Length == 0)) { return; } } } } [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true), SecurityPermission(SecurityAction.Assert, ControlPrincipal=true)] private bool TryNtlmAuthenticate() { try { using (NtlmAuth auth = new NtlmAuth()) { do { string blobString = null; string extraHeaders = this._knownRequestHeaders[0x18]; if ((extraHeaders != null) && extraHeaders.StartsWith("NTLM ", StringComparison.Ordinal)) { blobString = extraHeaders.Substring(5); } if (blobString != null) { if (!auth.Authenticate(blobString)) { this._connection.WriteErrorAndClose(0x193); return false; } if (auth.Completed) { goto Label_009A; } extraHeaders = "WWW-Authenticate: NTLM " + auth.Blob + "\r\n"; } else { extraHeaders = "WWW-Authenticate: NTLM\r\n"; } this.SkipAllPostedContent(); this._connection.WriteErrorWithExtraHeadersAndKeepAlive(0x191, extraHeaders); } while (this.TryParseRequest()); return false; Label_009A: if (this._host.GetProcessSID() != auth.SID) { this._connection.WriteErrorAndClose(0x193); return false; } } } catch { try { this._connection.WriteErrorAndClose(500); } catch { } return false; } return true; } private bool TryParseRequest() { this.Reset(); this.ReadAllHeaders(); //if (!this._connection.IsLocal) //{ // this._connection.WriteErrorAndClose(0x193); // return false; //} if (((this._headerBytes == null) || (this._endHeadersOffset < 0)) || ((this._headerByteStrings == null) || (this._headerByteStrings.Count == 0))) { this._connection.WriteErrorAndClose(400); return false; } this.ParseRequestLine(); if (this.IsBadPath()) { this._connection.WriteErrorAndClose(400); return false; } if (!this._host.IsVirtualPathInApp(this._path, out this._isClientScriptPath)) { this._connection.WriteErrorAndClose(0x194); return false; } this.ParseHeaders(); this.ParsePostedContent(); return true; } private bool TryReadAllHeaders() { byte[] src = this._connection.ReadRequestBytes(0x8000); if ((src == null) || (src.Length == 0)) { return false; } if (this._headerBytes != null) { int num = src.Length + this._headerBytes.Length; if (num > 0x8000) { return false; } byte[] dst = new byte[num]; Buffer.BlockCopy(this._headerBytes, 0, dst, 0, this._headerBytes.Length); Buffer.BlockCopy(src, 0, dst, this._headerBytes.Length, src.Length); this._headerBytes = dst; } else { this._headerBytes = src; } this._startHeadersOffset = -1; this._endHeadersOffset = -1; this._headerByteStrings = new ArrayList(); ByteParser parser = new ByteParser(this._headerBytes); while (true) { ByteString str = parser.ReadLine(); if (str == null) { break; } if (this._startHeadersOffset < 0) { this._startHeadersOffset = parser.CurrentOffset; } if (str.IsEmpty) { this._endHeadersOffset = parser.CurrentOffset; break; } this._headerByteStrings.Add(str); } return true; } private static string UrlEncodeRedirect(string path) { byte[] bytes = Encoding.UTF8.GetBytes(path); int length = bytes.Length; int num2 = 0; for (int i = 0; i < length; i++) { if ((bytes[i] & 0x80) != 0) { num2++; } } if (num2 > 0) { byte[] buffer2 = new byte[length + (num2 * 2)]; int num4 = 0; for (int j = 0; j < length; j++) { byte num6 = bytes[j]; if ((num6 & 0x80) == 0) { buffer2[num4++] = num6; } else { buffer2[num4++] = 0x25; buffer2[num4++] = (byte) IntToHex[(num6 >> 4) & 15]; buffer2[num4++] = (byte) IntToHex[num6 & 15]; } } path = Encoding.ASCII.GetString(buffer2); } if (path.IndexOf(' ') >= 0) { path = path.Replace(" ", "%20"); } return path; } } }
Server.cs
namespace Microsoft.VisualStudio.WebHost { using System; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Security.Principal; using System.Threading; using System.Web.Hosting; using System.Web; using System.Reflection; [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust"), PermissionSet(SecurityAction.LinkDemand, Name = "Everything")] public class Server : MarshalByRefObject { private ApplicationManager _appManager; private bool _disableDirectoryListing; private Host _host; private object _lockObject; private WaitCallback _onSocketAccept; private WaitCallback _onStart; private string _physicalPath; private int _port; private IntPtr _processToken; private string _processUser; private bool _requireAuthentication; private bool _shutdownInProgress; private Socket _socketIpv4; private Socket _socketIpv6; private string _virtualPath; private const int SecurityImpersonation = 2; private const int TOKEN_ALL_ACCESS = 0xf01ff; private const int TOKEN_EXECUTE = 0x20000; private const int TOKEN_IMPERSONATE = 4; private const int TOKEN_READ = 0x20008; public Server(int port, string virtualPath, string physicalPath) : this(port, virtualPath, physicalPath, false, false) { } public Server(int port, string virtualPath, string physicalPath, bool requireAuthentication) : this(port, virtualPath, physicalPath, requireAuthentication, false) { } public Server(int port, string virtualPath, string physicalPath, bool requireAuthentication, bool disableDirectoryListing) { this._lockObject = new object(); this._port = port; this._virtualPath = virtualPath; this._physicalPath = physicalPath.EndsWith(@"\", StringComparison.Ordinal) ? physicalPath : (physicalPath + @"\"); this._requireAuthentication = requireAuthentication; this._disableDirectoryListing = disableDirectoryListing; this._onSocketAccept = new WaitCallback(this.OnSocketAccept); this._onStart = new WaitCallback(this.OnStart); this._appManager = ApplicationManager.GetApplicationManager(); this.ObtainProcessToken(); } private Socket CreateSocketBindAndListen(AddressFamily family, IPAddress ipAddress, int port) { Socket socket = new Socket(family, SocketType.Stream, ProtocolType.Tcp) { ExclusiveAddressUse = false }; try { socket.Bind(new IPEndPoint(ipAddress, port)); } catch { socket.Close(); socket = null; throw; } socket.Listen(0x7fffffff); return socket; } [DllImport("KERNEL32.DLL", SetLastError = true)] private static extern IntPtr GetCurrentThread(); private Host GetHost() { if (this._shutdownInProgress) { return null; } Host host = this._host; if (host == null) { lock (this._lockObject) { host = this._host; if (host == null) { string appId = (this._virtualPath + this._physicalPath).ToLowerInvariant().GetHashCode().ToString("x", CultureInfo.InvariantCulture); //this._host = (Host) this._appManager.CreateObject(appId, typeof(Host), this._virtualPath, this._physicalPath, false); Type hostType = typeof(Host); var buildManagerHostType = typeof(HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost"); var buildManagerHost = _appManager.CreateObject(appId, buildManagerHostType, _virtualPath, _physicalPath, false); buildManagerHostType.InvokeMember("RegisterAssembly", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, buildManagerHost, new object[] { hostType.Assembly.FullName, hostType.Assembly.Location }); this._host = (Host) this._appManager.CreateObject(appId, hostType, this._virtualPath, this._physicalPath, false); this._host.Configure(this, this._port, this._virtualPath, this._physicalPath, this._requireAuthentication, this._disableDirectoryListing); host = this._host; } } } return host; } public IntPtr GetProcessToken() { return this._processToken; } public string GetProcessUser() { return this._processUser; } internal void HostStopped() { this._host = null; } [DllImport("ADVAPI32.DLL", SetLastError = true)] private static extern bool ImpersonateSelf(int level); public override object InitializeLifetimeService() { return null; } private void ObtainProcessToken() { if (ImpersonateSelf(2)) { OpenThreadToken(GetCurrentThread(), 0xf01ff, true, ref this._processToken); RevertToSelf(); this._processUser = WindowsIdentity.GetCurrent().Name; } } private void OnSocketAccept(object acceptedSocket) { if (!this._shutdownInProgress) { Microsoft.VisualStudio.WebHost.Connection conn = new Microsoft.VisualStudio.WebHost.Connection(this, (Socket)acceptedSocket); if (conn.WaitForRequestBytes() == 0) { conn.WriteErrorAndClose(400); } else { Host host = this.GetHost(); if (host == null) { conn.WriteErrorAndClose(500); } else { host.ProcessRequest(conn); } } } } private void OnStart(object listeningSocket) { while (!this._shutdownInProgress) { try { if (listeningSocket != null) { Socket state = ((Socket)listeningSocket).Accept(); ThreadPool.QueueUserWorkItem(this._onSocketAccept, state); } continue; } catch { Thread.Sleep(100); continue; } } } [DllImport("ADVAPI32.DLL", SetLastError = true)] private static extern int OpenThreadToken(IntPtr thread, int access, bool openAsSelf, ref IntPtr hToken); [DllImport("ADVAPI32.DLL", SetLastError = true)] private static extern int RevertToSelf(); public void Start() { bool flag = false; flag = Socket.OSSupportsIPv4; if (Socket.OSSupportsIPv6) { try { this._socketIpv6 = this.CreateSocketBindAndListen(AddressFamily.InterNetworkV6, IPAddress.IPv6Loopback, this._port); } catch (SocketException exception) { if ((exception.SocketErrorCode == SocketError.AddressAlreadyInUse) || !flag) { throw; } } } if (flag) { try { // Environment.MachineName IPHostEntry hosts = Dns.GetHostByName(Environment.MachineName); IPAddress address = IPAddress.Loopback; if (hosts.AddressList.Length > 0) address = hosts.AddressList[0]; this._socketIpv4 = this.CreateSocketBindAndListen(AddressFamily.InterNetwork, address, this._port); } catch (SocketException) { if (this._socketIpv6 == null) { throw; } } } if (this._socketIpv6 != null) { ThreadPool.QueueUserWorkItem(this._onStart, this._socketIpv6); } if (this._socketIpv4 != null) { ThreadPool.QueueUserWorkItem(this._onStart, this._socketIpv4); } } public void Stop() { this._shutdownInProgress = true; try { if (this._socketIpv4 != null) { this._socketIpv4.Close(); } if (this._socketIpv6 != null) { this._socketIpv6.Close(); } } catch { } finally { this._socketIpv4 = null; this._socketIpv6 = null; } try { if (this._host != null) { this._host.Shutdown(); } while (this._host != null) { Thread.Sleep(100); } } catch { } finally { this._host = null; } } public string PhysicalPath { get { return this._physicalPath; } } public int Port { get { return this._port; } } public string RootUrl { get { if (this._port != 80) { return ("http://localhost:" + this._port + this._virtualPath); } return ("http://localhost" + this._virtualPath); } } public string VirtualPath { get { return this._virtualPath; } } } }
调用代码:
Server s = new Server(49152, "/", @"C:\Users\majiang\Documents\Visual Studio 2010\Projects\ConsoleApp\WebApp");
s.Start();
欢迎大家拍砖
windows技术爱好者