@ -0,0 +1,7 @@
|
||||
del ..\deploy\*.* /s/q
|
||||
xcopy bin\x86 ..\deploy /S /I /F /Y <nul:
|
||||
del ..\deploy\*vshost* /s
|
||||
del ..\deploy\release\*.pdb /s
|
||||
del ..\deploy\*.db3 /s
|
||||
rem tree ..\deploy /f>..\deploy.txt
|
||||
copy ..\*.txt ..\deploy\ /Y
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<generatePublisherEvidence enabled="false"/>
|
||||
</runtime>
|
||||
<startup useLegacyV2RuntimeActivationPolicy="true">
|
||||
<supportedRuntime version="v4.0" />
|
||||
</startup>
|
||||
</configuration>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<generatePublisherEvidence enabled="false"/>
|
||||
</runtime>
|
||||
<startup useLegacyV2RuntimeActivationPolicy="true">
|
||||
<supportedRuntime version="v4.0" />
|
||||
</startup>
|
||||
</configuration>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<generatePublisherEvidence enabled="false"/>
|
||||
</runtime>
|
||||
<startup useLegacyV2RuntimeActivationPolicy="true">
|
||||
<supportedRuntime version="v4.0" />
|
||||
</startup>
|
||||
</configuration>
|
@ -0,0 +1,410 @@
|
||||
// **********************************************************************************
|
||||
// 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.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using CassiniDev.ServerLog;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
public class Connection : MarshalByRefObject
|
||||
{
|
||||
private const int HttpForbidden = 403;
|
||||
|
||||
private const int HttpOK = 200;
|
||||
|
||||
private readonly MemoryStream _responseContent;
|
||||
|
||||
private readonly Server _server;
|
||||
private LogInfo _requestLog;
|
||||
private LogInfo _responseLog;
|
||||
|
||||
private Socket _socket;
|
||||
|
||||
internal Connection(Server server, Socket socket)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
_responseContent = new MemoryStream();
|
||||
_server = server;
|
||||
_socket = socket;
|
||||
InitializeLogInfo();
|
||||
}
|
||||
|
||||
public bool Connected
|
||||
{
|
||||
get { return _socket.Connected; }
|
||||
}
|
||||
|
||||
public Guid Id { get; private set; }
|
||||
|
||||
public string LocalIP
|
||||
{
|
||||
get
|
||||
{
|
||||
IPEndPoint ep = (IPEndPoint) _socket.LocalEndPoint;
|
||||
return (ep != null && ep.Address != null) ? ep.Address.ToString() : "127.0.0.1";
|
||||
}
|
||||
}
|
||||
|
||||
public string RemoteIP
|
||||
{
|
||||
get
|
||||
{
|
||||
IPEndPoint ep = (IPEndPoint) _socket.RemoteEndPoint;
|
||||
return (ep != null && ep.Address != null) ? ep.Address.ToString() : "127.0.0.1";
|
||||
}
|
||||
}
|
||||
|
||||
public LogInfo RequestLog
|
||||
{
|
||||
get { return _requestLog; }
|
||||
}
|
||||
|
||||
public LogInfo ResponseLog
|
||||
{
|
||||
get { return _responseLog; }
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
FinalizeLogInfo();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void LogRequest(string pathTranslated, string url)
|
||||
{
|
||||
_requestLog.PathTranslated = pathTranslated;
|
||||
|
||||
_requestLog.Url = url;
|
||||
}
|
||||
|
||||
public void LogRequestBody(byte[] content)
|
||||
{
|
||||
_requestLog.Body = content;
|
||||
}
|
||||
|
||||
public void LogRequestHeaders(string headers)
|
||||
{
|
||||
_requestLog.Headers = headers;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void Write100Continue()
|
||||
{
|
||||
WriteEntireResponseFromString(100, null, null, true);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
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 = Common.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);
|
||||
_responseLog.Headers = headers;
|
||||
_responseLog.StatusCode = HttpOK;
|
||||
_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_responseLog.Headers = headers;
|
||||
_responseLog.StatusCode = statusCode;
|
||||
_socket.Send(Encoding.UTF8.GetBytes(headers + body));
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!keepAlive)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteErrorAndClose(int statusCode, string message)
|
||||
{
|
||||
WriteEntireResponseFromString(statusCode, null, GetErrorResponseBody(statusCode, message), false);
|
||||
}
|
||||
|
||||
public void WriteErrorAndClose(int statusCode)
|
||||
{
|
||||
WriteErrorAndClose(statusCode, null);
|
||||
}
|
||||
|
||||
public void WriteErrorWithExtraHeadersAndKeepAlive(int statusCode, string extraHeaders)
|
||||
{
|
||||
WriteEntireResponseFromString(statusCode, extraHeaders, GetErrorResponseBody(statusCode, null), true);
|
||||
}
|
||||
|
||||
public void WriteHeaders(int statusCode, String extraHeaders)
|
||||
{
|
||||
string headers = MakeResponseHeaders(statusCode, extraHeaders, -1, false);
|
||||
|
||||
_responseLog.Headers = headers;
|
||||
_responseLog.StatusCode = statusCode;
|
||||
|
||||
try
|
||||
{
|
||||
_socket.Send(Encoding.UTF8.GetBytes(headers));
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void FinalizeLogInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
_responseLog.Body = _responseContent.ToArray();
|
||||
_responseContent.Dispose();
|
||||
_responseLog.Created = DateTime.Now;
|
||||
_responseLog.Url = _requestLog.Url;
|
||||
_responseLog.PathTranslated = _requestLog.PathTranslated;
|
||||
_responseLog.Identity = _requestLog.Identity;
|
||||
_responseLog.PhysicalPath = _requestLog.PhysicalPath;
|
||||
}
|
||||
// ReSharper disable EmptyGeneralCatchClause
|
||||
catch
|
||||
// ReSharper restore EmptyGeneralCatchClause
|
||||
{
|
||||
// log error to text
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,296 @@
|
||||
// **********************************************************************************
|
||||
// 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.Globalization;
|
||||
using System.Security.Permissions;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
/// <summary>
|
||||
/// 01/01/10 sky: added HttpRuntime.Close to IRegisteredObject.Stop to eliminate
|
||||
/// System.AppDomainUnloadedException when running tests in NUnit GuiRunner.
|
||||
/// reference: http://stackoverflow.com/questions/561402/cassini-webserver-webdev-nunit-and-appdomainunloadedexception
|
||||
/// need to test thoroughly but seems to work just fine with no ill effects
|
||||
/// 01.03.10 sky: removed the HttpRuntime.Close because, even though it tests fine, I am not entirely certain it is in the right place
|
||||
/// and since I am no longer recommending that the server be used as a library in testing (run a console instance in a new process).
|
||||
///
|
||||
/// </summary>
|
||||
internal 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 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);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
// Add a pending call to make sure our thread doesn't get killed
|
||||
AddPendingCall();
|
||||
|
||||
try
|
||||
{
|
||||
new Request(_server, this, conn).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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
// **********************************************************************************
|
||||
// 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 CassiniDev
|
||||
{
|
||||
/// <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> Cassini 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> Cassini 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
// **********************************************************************************
|
||||
// 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.Security;
|
||||
using System.Security.Principal;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal sealed class NtlmAuth : IDisposable
|
||||
{
|
||||
private readonly bool _credentialsHandleAcquired;
|
||||
|
||||
private string _blob;
|
||||
|
||||
private bool _completed;
|
||||
|
||||
private Interop.SecHandle _credentialsHandle;
|
||||
|
||||
private Interop.SecBuffer _inputBuffer;
|
||||
private Interop.SecBufferDesc _inputBufferDesc;
|
||||
|
||||
private Interop.SecBuffer _outputBuffer;
|
||||
|
||||
private Interop.SecBufferDesc _outputBufferDesc;
|
||||
|
||||
private Interop.SecHandle _securityContext;
|
||||
|
||||
private bool _securityContextAcquired;
|
||||
|
||||
private uint _securityContextAttributes;
|
||||
|
||||
private SecurityIdentifier _sid;
|
||||
|
||||
private long _timestamp;
|
||||
|
||||
public NtlmAuth()
|
||||
{
|
||||
if (
|
||||
Interop.AcquireCredentialsHandle(null, "NTLM", 1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero,
|
||||
ref _credentialsHandle, ref _timestamp) != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
_credentialsHandleAcquired = true;
|
||||
}
|
||||
|
||||
public string Blob
|
||||
{
|
||||
get { return _blob; }
|
||||
}
|
||||
|
||||
public bool Completed
|
||||
{
|
||||
get { return _completed; }
|
||||
}
|
||||
|
||||
public SecurityIdentifier SID
|
||||
{
|
||||
get { return _sid; }
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
FreeUnmanagedResources();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public unsafe bool Authenticate(string blobString)
|
||||
{
|
||||
_blob = null;
|
||||
byte[] buffer = Convert.FromBase64String(blobString);
|
||||
byte[] inArray = new byte[0x4000];
|
||||
fixed (void* ptrRef = &_securityContext)
|
||||
{
|
||||
fixed (void* ptrRef2 = &_inputBuffer)
|
||||
{
|
||||
fixed (void* ptrRef3 = &_outputBuffer)
|
||||
{
|
||||
fixed (void* ptrRef4 = buffer)
|
||||
{
|
||||
fixed (void* ptrRef5 = inArray)
|
||||
{
|
||||
IntPtr zero = IntPtr.Zero;
|
||||
if (_securityContextAcquired)
|
||||
{
|
||||
zero = (IntPtr) ptrRef;
|
||||
}
|
||||
_inputBufferDesc.ulVersion = 0;
|
||||
_inputBufferDesc.cBuffers = 1;
|
||||
_inputBufferDesc.pBuffers = (IntPtr) ptrRef2;
|
||||
_inputBuffer.cbBuffer = (uint) buffer.Length;
|
||||
_inputBuffer.BufferType = 2;
|
||||
_inputBuffer.pvBuffer = (IntPtr) ptrRef4;
|
||||
_outputBufferDesc.ulVersion = 0;
|
||||
_outputBufferDesc.cBuffers = 1;
|
||||
_outputBufferDesc.pBuffers = (IntPtr) ptrRef3;
|
||||
_outputBuffer.cbBuffer = (uint) inArray.Length;
|
||||
_outputBuffer.BufferType = 2;
|
||||
_outputBuffer.pvBuffer = (IntPtr) ptrRef5;
|
||||
int num = Interop.AcceptSecurityContext(ref _credentialsHandle, zero,
|
||||
ref _inputBufferDesc, 20,
|
||||
0, ref _securityContext, ref _outputBufferDesc,
|
||||
ref _securityContextAttributes, ref _timestamp);
|
||||
if (num == 0x90312)
|
||||
{
|
||||
_securityContextAcquired = true;
|
||||
_blob = Convert.ToBase64String(inArray, 0, (int) _outputBuffer.cbBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
IntPtr phToken = IntPtr.Zero;
|
||||
if (Interop.QuerySecurityContextToken(ref _securityContext, ref phToken) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
using (WindowsIdentity identity = new WindowsIdentity(phToken))
|
||||
{
|
||||
_sid = identity.User;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interop.CloseHandle(phToken);
|
||||
}
|
||||
_completed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
~NtlmAuth()
|
||||
{
|
||||
FreeUnmanagedResources();
|
||||
}
|
||||
|
||||
private void FreeUnmanagedResources()
|
||||
{
|
||||
if (_securityContextAcquired)
|
||||
{
|
||||
Interop.DeleteSecurityContext(ref _securityContext);
|
||||
}
|
||||
if (_credentialsHandleAcquired)
|
||||
{
|
||||
Interop.FreeCredentialsHandle(ref _credentialsHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// **********************************************************************************
|
||||
// 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 CassiniDev.ServerLog;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
public class RequestEventArgs : EventArgs
|
||||
{
|
||||
private readonly Guid _id;
|
||||
|
||||
private readonly LogInfo _requestLog;
|
||||
|
||||
private readonly LogInfo _responseLog;
|
||||
|
||||
public RequestEventArgs(Guid id, LogInfo requestLog, LogInfo responseLog)
|
||||
{
|
||||
_requestLog = requestLog;
|
||||
_responseLog = responseLog;
|
||||
_id = id;
|
||||
}
|
||||
|
||||
public Guid Id
|
||||
{
|
||||
get { return _id; }
|
||||
}
|
||||
|
||||
public LogInfo RequestLog
|
||||
{
|
||||
get { return _requestLog; }
|
||||
}
|
||||
|
||||
public LogInfo ResponseLog
|
||||
{
|
||||
get { return _responseLog; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,523 @@
|
||||
// **********************************************************************************
|
||||
// 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.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.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using CassiniDev.ServerLog;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
[PermissionSet(SecurityAction.LinkDemand, Name = "Everything"),
|
||||
PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
|
||||
public class Server : MarshalByRefObject, IDisposable
|
||||
{
|
||||
private readonly ApplicationManager _appManager;
|
||||
|
||||
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;
|
||||
|
||||
public Server(int port, string virtualPath, string physicalPath)
|
||||
: this(port, virtualPath, physicalPath, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
public Server(int port, string physicalPath)
|
||||
: this(port, "/", physicalPath, IPAddress.Loopback)
|
||||
{
|
||||
}
|
||||
|
||||
public Server(string physicalPath)
|
||||
: this(CassiniNetworkUtils.GetAvailablePort(32768, 65535, IPAddress.Loopback, false), physicalPath)
|
||||
{
|
||||
}
|
||||
|
||||
public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress, string hostName,
|
||||
int timeout, bool requireAuthentication)
|
||||
: this(port, virtualPath, physicalPath, ipAddress, hostName, timeout, requireAuthentication, 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, IPAddress ipAddress, string hostName)
|
||||
: this(port, virtualPath, physicalPath, ipAddress, hostName, 0, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress, string hostName,
|
||||
int timeout, bool requireAuthentication, bool disableDirectoryListing)
|
||||
: this(port, virtualPath, physicalPath, requireAuthentication, disableDirectoryListing)
|
||||
{
|
||||
_ipAddress = ipAddress;
|
||||
_hostName = hostName;
|
||||
_timeoutInterval = timeout;
|
||||
}
|
||||
|
||||
public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress)
|
||||
: this(port, virtualPath, physicalPath, ipAddress, null, 0, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
public Server(int port, string virtualPath, string physicalPath, bool requireAuthentication,
|
||||
bool disableDirectoryListing)
|
||||
{
|
||||
_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 + "\\";
|
||||
_appManager = ApplicationManager.GetApplicationManager();
|
||||
ObtainProcessToken();
|
||||
}
|
||||
|
||||
public Server(string physicalPath, bool requireAuthentication)
|
||||
: this(
|
||||
CassiniNetworkUtils.GetAvailablePort(32768, 65535, IPAddress.Loopback, false), "/", physicalPath,
|
||||
requireAuthentication)
|
||||
{
|
||||
}
|
||||
|
||||
public Server(int port, string virtualPath, string physicalPath, IPAddress ipAddress, string hostName,
|
||||
int timeout)
|
||||
: this(port, virtualPath, physicalPath, ipAddress, hostName, timeout, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
public bool DisableDirectoryListing
|
||||
{
|
||||
get { return _disableDirectoryListing; }
|
||||
}
|
||||
|
||||
public bool RequireAuthentication
|
||||
{
|
||||
get { return _requireAuthentication; }
|
||||
}
|
||||
|
||||
public int TimeoutInterval
|
||||
{
|
||||
get { return _timeoutInterval; }
|
||||
}
|
||||
|
||||
public string HostName
|
||||
{
|
||||
get { return _hostName; }
|
||||
}
|
||||
|
||||
public IPAddress IPAddress
|
||||
{
|
||||
get { return _ipAddress; }
|
||||
}
|
||||
|
||||
public string PhysicalPath
|
||||
{
|
||||
get { return _physicalPath; }
|
||||
}
|
||||
|
||||
public int Port
|
||||
{
|
||||
get { return _port; }
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public string VirtualPath
|
||||
{
|
||||
get { return _virtualPath; }
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
ShutDown();
|
||||
}
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public event EventHandler<RequestEventArgs> RequestComplete;
|
||||
|
||||
public event EventHandler TimedOut;
|
||||
|
||||
public IntPtr GetProcessToken()
|
||||
{
|
||||
return _processToken;
|
||||
}
|
||||
|
||||
public string GetProcessUser()
|
||||
{
|
||||
return _processUser;
|
||||
}
|
||||
|
||||
public void HostStopped()
|
||||
{
|
||||
_host = null;
|
||||
}
|
||||
|
||||
[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>
|
||||
public void OnRequestEnd(Connection conn)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnRequestComplete(conn.Id, conn.RequestLog.Clone(), conn.ResponseLog.Clone());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// swallow - we don't want consumer killing the server
|
||||
}
|
||||
RemotingServices.Disconnect(conn);
|
||||
DecrementRequestCount();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
~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>
|
||||
/// <returns></returns>
|
||||
/// <remarks>This is Dmitry's hack to enable running outside of GAC</remarks>
|
||||
private object CreateWorkerAppDomainWithHost(string virtualPath, string physicalPath, Type hostType)
|
||||
{
|
||||
// this creates worker app domain in a way that host doesn't need to be in GAC or bin
|
||||
// using BuildManagerHost via private reflection
|
||||
string uniqueAppString = string.Concat(virtualPath, physicalPath).ToLowerInvariant();
|
||||
string appId = (uniqueAppString.GetHashCode()).ToString("x", CultureInfo.InvariantCulture);
|
||||
|
||||
// create BuildManagerHost in the worker app domain
|
||||
//ApplicationManager appManager = ApplicationManager.GetApplicationManager();
|
||||
Type buildManagerHostType = typeof (HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost");
|
||||
IRegisteredObject buildManagerHost = _appManager.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
|
||||
return _appManager.CreateObject(appId, hostType, virtualPath, physicalPath, false);
|
||||
}
|
||||
|
||||
private void DecrementRequestCount()
|
||||
{
|
||||
_requestCount--;
|
||||
|
||||
if (_requestCount < 1)
|
||||
{
|
||||
_requestCount = 0;
|
||||
|
||||
if (_timeoutInterval > 0)
|
||||
{
|
||||
_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));
|
||||
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));
|
||||
host.Configure(this, _port, _virtualPath, _physicalPath, _requireAuthentication,
|
||||
_disableDirectoryListing);
|
||||
_host = host;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
private void IncrementRequestCount()
|
||||
{
|
||||
_requestCount++;
|
||||
_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, LogInfo requestLog, LogInfo responseLog)
|
||||
{
|
||||
EventHandler<RequestEventArgs> complete = RequestComplete;
|
||||
|
||||
if (complete != null)
|
||||
{
|
||||
complete(this, new RequestEventArgs(id, requestLog, responseLog));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ShutDown()
|
||||
{
|
||||
_shutdownInProgress = true;
|
||||
|
||||
try
|
||||
{
|
||||
if (_socket != null)
|
||||
{
|
||||
_socket.Close();
|
||||
}
|
||||
}
|
||||
// ReSharper disable EmptyGeneralCatchClause
|
||||
catch
|
||||
// ReSharper restore EmptyGeneralCatchClause
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socket = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_host != null)
|
||||
{
|
||||
_host.Shutdown();
|
||||
}
|
||||
|
||||
while (_host != null)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
// ReSharper disable EmptyGeneralCatchClause
|
||||
catch
|
||||
// ReSharper restore EmptyGeneralCatchClause
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
_host = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeOut(object ignored)
|
||||
{
|
||||
TimeOut();
|
||||
}
|
||||
|
||||
public void TimeOut()
|
||||
{
|
||||
ShutDown();
|
||||
OnTimeOut();
|
||||
}
|
||||
|
||||
private void OnTimeOut()
|
||||
{
|
||||
EventHandler handler = TimedOut;
|
||||
if (handler != null) handler(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
// **********************************************************************************
|
||||
// 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;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev.UIComponents
|
||||
{
|
||||
public sealed class CommandLine
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly string[] _arguments;
|
||||
|
||||
private readonly bool _showHelp;
|
||||
private IDictionary _options;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public CommandLine(string[] args)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
char ch = args[i][0];
|
||||
if ((ch != '/') && (ch != '-'))
|
||||
{
|
||||
list.Add(args[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = args[i].IndexOf(':');
|
||||
if (index == -1)
|
||||
{
|
||||
string strA = args[i].Substring(1);
|
||||
if ((string.Compare(strA, "help", StringComparison.OrdinalIgnoreCase) == 0) || strA.Equals("?"))
|
||||
{
|
||||
_showHelp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Options[strA] = string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Options[args[i].Substring(1, index - 1)] = args[i].Substring(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
_arguments = (string[]) list.ToArray(typeof (string));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public string[] Arguments
|
||||
{
|
||||
get { return _arguments; }
|
||||
}
|
||||
|
||||
public IDictionary Options
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_options == null)
|
||||
{
|
||||
_options = new HybridDictionary(true);
|
||||
}
|
||||
return _options;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowHelp
|
||||
{
|
||||
get { return _showHelp; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,443 @@
|
||||
// **********************************************************************************
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
/// <summary>
|
||||
/// Command line arguments
|
||||
///
|
||||
/// fixed 5/24/10 - quoted embedded spaces in ToString
|
||||
/// </summary>
|
||||
public class CommandLineArguments
|
||||
{
|
||||
#region Properties
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "ah", DefaultValue = false,
|
||||
HelpText = "If true add entry to Windows hosts file. Requires write permissions to hosts file.")] public
|
||||
bool AddHost;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "a", LongName = "path",
|
||||
HelpText = "Physical location of content.")] public string
|
||||
ApplicationPath;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, LongName = "log", DefaultValue = false, HelpText = "Enable logging.")] public
|
||||
bool EnableLogging;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "h", LongName = "host",
|
||||
HelpText = "Host name used for app root url. Optional unless AddHost is true.")] public string HostName;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "i", LongName = "ip",
|
||||
HelpText = "IP address to listen to. Ignored if IPMode != Specific")] public string IPAddress;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "im", DefaultValue = IPMode.Loopback, HelpText = "",
|
||||
LongName = "ipMode")] public
|
||||
IPMode IPMode;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "v6", DefaultValue = false,
|
||||
HelpText = "If IPMode 'Any' or 'LoopBack' are specified use the V6 address", LongName = "ipV6")] public bool
|
||||
IPv6;
|
||||
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, LongName = "nodirlist", DefaultValue = false,
|
||||
HelpText = "Disable diretory listing")] public bool Nodirlist;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, LongName = "ntlm", DefaultValue = false, HelpText = "Run as current identity"
|
||||
)] public bool Ntlm;
|
||||
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "p", LongName = "port",
|
||||
HelpText = "Port to listen to. Ignored if PortMode=FirstAvailable.", DefaultValue = 0)] public int Port;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "pm", HelpText = "", LongName = "portMode",
|
||||
DefaultValue = PortMode.FirstAvailable)] public PortMode PortMode;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "pre", DefaultValue = 65535, LongName = "highPort",
|
||||
HelpText = "End of port range. Ignored if PortMode != FirstAvailable")] public int PortRangeEnd = 9000;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "prs", DefaultValue = 32768, LongName = "lowPort",
|
||||
HelpText = "Start of port range. Ignored if PortMode != FirstAvailable")] public int PortRangeStart =
|
||||
8080;
|
||||
|
||||
[DefaultArgument(ArgumentType.AtMostOnce, DefaultValue = RunMode.Server, HelpText = "[Server|Hostsfile]")] public RunMode RunMode;
|
||||
[Argument(ArgumentType.AtMostOnce, LongName = "silent", DefaultValue = false, HelpText = "Fail silently")] public bool Silent;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "t", DefaultValue = 0, LongName = "timeout",
|
||||
HelpText = "Length of time, in ms, to wait for a request before stopping the server. 0 = no timeout.")] public int TimeOut;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "v", LongName = "vpath", DefaultValue = "/",
|
||||
HelpText = "Optional. default value '/'"
|
||||
)] public string VirtualPath = "/";
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "vs", DefaultValue = false,
|
||||
HelpText = "If true run in Visual Studio Development Server mode - readonly UI with single option to quit.."
|
||||
)] public
|
||||
bool VisualStudio;
|
||||
|
||||
[Argument(ArgumentType.AtMostOnce, ShortName = "w", DefaultValue = 0, LongName = "wait",
|
||||
HelpText =
|
||||
"Length of time, in ms, to wait for a specific port before throwing an exception or exiting. 0 = don't wait."
|
||||
)] public int WaitForPort;
|
||||
|
||||
#endregion
|
||||
|
||||
public string[] ToArgs()
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
if (RunMode != RunMode.Server)
|
||||
{
|
||||
result.Add(string.Format("{0}", RunMode));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(ApplicationPath))
|
||||
{
|
||||
result.Add(string.Format("/a:{0}", ApplicationPath.Contains("") ? String.Format("\"{0}\"", ApplicationPath) : ApplicationPath));
|
||||
}
|
||||
result.Add(string.Format("/v:{0}", VirtualPath.Contains("") ? String.Format("\"{0}\"", VirtualPath) : VirtualPath));
|
||||
|
||||
if (!string.IsNullOrEmpty(HostName))
|
||||
{
|
||||
result.Add(string.Format("/h:{0}", HostName.Contains("") ? String.Format("\"{0}\"", HostName) : HostName));
|
||||
}
|
||||
if (AddHost)
|
||||
{
|
||||
result.Add("/ah");
|
||||
}
|
||||
|
||||
if (IPMode != IPMode.Loopback)
|
||||
{
|
||||
result.Add(string.Format("/im:{0}", IPMode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(IPAddress))
|
||||
{
|
||||
result.Add(string.Format("/i:{0}", IPAddress));
|
||||
}
|
||||
|
||||
if (IPv6)
|
||||
{
|
||||
result.Add("/v6");
|
||||
}
|
||||
|
||||
if (VisualStudio)
|
||||
{
|
||||
result.Add("/vs");
|
||||
}
|
||||
|
||||
if (PortMode != PortMode.FirstAvailable)
|
||||
{
|
||||
result.Add(string.Format("/pm:{0}", PortMode));
|
||||
}
|
||||
|
||||
if (Port != 0)
|
||||
{
|
||||
result.Add(string.Format("/p:{0}", Port));
|
||||
}
|
||||
|
||||
if (PortRangeStart != 32768)
|
||||
{
|
||||
result.Add(string.Format("/prs:{0}", PortRangeStart));
|
||||
}
|
||||
if (PortRangeEnd != 65535)
|
||||
{
|
||||
result.Add(string.Format("/pre:{0}", PortRangeEnd));
|
||||
}
|
||||
if (TimeOut > 0)
|
||||
{
|
||||
result.Add(string.Format("/t:{0}", TimeOut));
|
||||
}
|
||||
if (WaitForPort > 0)
|
||||
{
|
||||
result.Add(string.Format("/w:{0}", WaitForPort));
|
||||
}
|
||||
|
||||
if (Ntlm)
|
||||
{
|
||||
result.Add("/ntlm");
|
||||
}
|
||||
if (Silent)
|
||||
{
|
||||
result.Add("/silent");
|
||||
}
|
||||
if (Nodirlist)
|
||||
{
|
||||
result.Add("/nodirlist");
|
||||
}
|
||||
if (EnableLogging)
|
||||
{
|
||||
result.Add("/log");
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(" ", ToArgs());
|
||||
//StringBuilder sb = new StringBuilder();
|
||||
//if (RunMode != RunMode.Server)
|
||||
//{
|
||||
// sb.AppendFormat("{0}", RunMode);
|
||||
//}
|
||||
//if (!string.IsNullOrEmpty(ApplicationPath))
|
||||
//{
|
||||
// sb.AppendFormat(" /a:{0}", ApplicationPath.Contains(" ") ? String.Format("\"{0}\"", ApplicationPath) : ApplicationPath);
|
||||
//}
|
||||
//sb.AppendFormat(" /v:{0}", VirtualPath.Contains(" ") ? String.Format("\"{0}\"", VirtualPath) : VirtualPath);
|
||||
|
||||
//if (!string.IsNullOrEmpty(HostName))
|
||||
//{
|
||||
// sb.AppendFormat(" /h:{0}", HostName.Contains(" ") ? String.Format("\"{0}\"", HostName) : HostName);
|
||||
//}
|
||||
//if (AddHost)
|
||||
//{
|
||||
// sb.Append(" /ah");
|
||||
//}
|
||||
|
||||
//if (IPMode != IPMode.Loopback)
|
||||
//{
|
||||
// sb.AppendFormat(" /im:{0}", IPMode);
|
||||
//}
|
||||
|
||||
//if (!string.IsNullOrEmpty(IPAddress))
|
||||
//{
|
||||
// sb.AppendFormat(" /i:{0}", IPAddress);
|
||||
//}
|
||||
|
||||
//if (IPv6)
|
||||
//{
|
||||
// sb.Append(" /v6");
|
||||
//}
|
||||
|
||||
//if (VisualStudio)
|
||||
//{
|
||||
// sb.Append(" /vs");
|
||||
//}
|
||||
|
||||
//if (PortMode != PortMode.FirstAvailable)
|
||||
//{
|
||||
// sb.AppendFormat(" /pm:{0}", PortMode);
|
||||
//}
|
||||
|
||||
//if (Port != 0)
|
||||
//{
|
||||
// sb.AppendFormat(" /p:{0}", Port);
|
||||
//}
|
||||
|
||||
//if (PortRangeStart != 32768)
|
||||
//{
|
||||
// sb.AppendFormat(" /prs:{0}", PortRangeStart);
|
||||
//}
|
||||
//if (PortRangeEnd != 65535)
|
||||
//{
|
||||
// sb.AppendFormat(" /pre:{0}", PortRangeEnd);
|
||||
//}
|
||||
//if (TimeOut > 0)
|
||||
//{
|
||||
// sb.AppendFormat(" /t:{0}", TimeOut);
|
||||
//}
|
||||
//if (WaitForPort > 0)
|
||||
//{
|
||||
// sb.AppendFormat(" /w:{0}", WaitForPort);
|
||||
//}
|
||||
|
||||
//if (Ntlm)
|
||||
//{
|
||||
// sb.Append(" /ntlm");
|
||||
//}
|
||||
//if (Silent)
|
||||
//{
|
||||
// sb.Append(" /silent");
|
||||
//}
|
||||
//if (Nodirlist)
|
||||
//{
|
||||
// sb.Append(" /nodirlist");
|
||||
//}
|
||||
//if (EnableLogging)
|
||||
//{
|
||||
// sb.Append(" /log");
|
||||
//}
|
||||
//return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
internal void Validate()
|
||||
{
|
||||
if (string.IsNullOrEmpty(ApplicationPath))
|
||||
{
|
||||
throw new CassiniException(SR.ErrApplicationPathIsNull, ErrorField.ApplicationPath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ApplicationPath = Path.GetFullPath(ApplicationPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
if (!Directory.Exists(ApplicationPath))
|
||||
{
|
||||
throw new CassiniException(SR.WebdevDirNotExist, ErrorField.ApplicationPath);
|
||||
}
|
||||
|
||||
ApplicationPath = ApplicationPath.Trim('\"').TrimEnd('\\');
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(VirtualPath))
|
||||
{
|
||||
VirtualPath = VirtualPath.Trim('\"');
|
||||
VirtualPath = VirtualPath.Trim('/');
|
||||
VirtualPath = "/" + VirtualPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
VirtualPath = "/";
|
||||
}
|
||||
|
||||
|
||||
if (!VirtualPath.StartsWith("/"))
|
||||
{
|
||||
VirtualPath = "/" + VirtualPath;
|
||||
}
|
||||
|
||||
|
||||
if (AddHost && string.IsNullOrEmpty(HostName))
|
||||
{
|
||||
throw new CassiniException(SR.ErrInvalidHostname, ErrorField.HostName);
|
||||
}
|
||||
|
||||
|
||||
IPAddress = ParseIP(IPMode, IPv6, IPAddress).ToString();
|
||||
|
||||
|
||||
if (VisualStudio) // then STOP HERE.
|
||||
{
|
||||
// It is fortunate that in order to provide api parity with WebDev
|
||||
// we do not need to port scan. Visual Studio balks and refuses to
|
||||
// attach if we monkey around and open ports.
|
||||
Port = Port == 0 ? 80 : Port;
|
||||
PortMode = PortMode.Specific;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (PortMode)
|
||||
{
|
||||
case PortMode.FirstAvailable:
|
||||
|
||||
if (PortRangeStart < 1)
|
||||
{
|
||||
throw new CassiniException(SR.ErrInvalidPortRangeValue, ErrorField.PortRangeStart);
|
||||
}
|
||||
|
||||
if (PortRangeEnd < 1)
|
||||
{
|
||||
throw new CassiniException(SR.ErrInvalidPortRangeValue, ErrorField.PortRangeEnd);
|
||||
}
|
||||
|
||||
if (PortRangeStart > PortRangeEnd)
|
||||
{
|
||||
throw new CassiniException(SR.ErrPortRangeEndMustBeEqualOrGreaterThanPortRangeSta,
|
||||
ErrorField.PortRange);
|
||||
}
|
||||
Port = CassiniNetworkUtils.GetAvailablePort(PortRangeStart, PortRangeEnd,
|
||||
System.Net.IPAddress.Parse(IPAddress), true);
|
||||
|
||||
if (Port == 0)
|
||||
{
|
||||
throw new CassiniException(SR.ErrNoAvailablePortFound, ErrorField.PortRange);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PortMode.Specific:
|
||||
|
||||
if ((Port < 1) || (Port > 0xffff))
|
||||
{
|
||||
throw new CassiniException(SR.ErrPortOutOfRange, ErrorField.Port);
|
||||
}
|
||||
|
||||
|
||||
// start waiting....
|
||||
//TODO: design this hack away.... why am I waiting in a validation method?
|
||||
int now = Environment.TickCount;
|
||||
|
||||
// wait until either 1) the specified port is available or 2) the specified amount of time has passed
|
||||
while (Environment.TickCount < now + WaitForPort &&
|
||||
CassiniNetworkUtils.GetAvailablePort(Port, Port, System.Net.IPAddress.Parse(IPAddress), true) !=
|
||||
Port)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
// is the port available?
|
||||
if (CassiniNetworkUtils.GetAvailablePort(Port, Port, System.Net.IPAddress.Parse(IPAddress), true) !=
|
||||
Port)
|
||||
{
|
||||
throw new CassiniException(SR.ErrPortIsInUse, ErrorField.Port);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
throw new CassiniException(SR.ErrInvalidPortMode, ErrorField.None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts CommandLineArgument values to an IP address if possible.
|
||||
/// Throws Exception if not.
|
||||
/// </summary>
|
||||
/// <param name="ipmode"></param>
|
||||
/// <param name="v6"></param>
|
||||
/// <param name="ipString"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="CassiniException">If IPMode is invalid</exception>
|
||||
/// <exception cref="CassiniException">If IPMode is 'Specific' and ipString is invalid</exception>
|
||||
public static IPAddress ParseIP(IPMode ipmode, bool v6, string ipString)
|
||||
{
|
||||
IPAddress ip;
|
||||
switch (ipmode)
|
||||
{
|
||||
case IPMode.Loopback:
|
||||
|
||||
ip = v6 ? System.Net.IPAddress.IPv6Loopback : System.Net.IPAddress.Loopback;
|
||||
break;
|
||||
case IPMode.Any:
|
||||
ip = v6 ? System.Net.IPAddress.IPv6Any : System.Net.IPAddress.Any;
|
||||
break;
|
||||
case IPMode.Specific:
|
||||
|
||||
if (!System.Net.IPAddress.TryParse(ipString, out ip))
|
||||
{
|
||||
throw new CassiniException(SR.ErrInvalidIPAddress, ErrorField.IPAddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new CassiniException(SR.ErrInvalidIPMode, ErrorField.None);
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
// **********************************************************************************
|
||||
// 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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
public static class HostsFile
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ipAddress"></param>
|
||||
/// <param name="hostname"></param>
|
||||
/// <returns></returns>
|
||||
public static int AddHostEntry(string ipAddress, string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetHostsEntry(true, ipAddress, hostname);
|
||||
return 0;
|
||||
}
|
||||
// ReSharper disable EmptyGeneralCatchClause
|
||||
catch
|
||||
// ReSharper restore EmptyGeneralCatchClause
|
||||
{
|
||||
}
|
||||
string executablePath = Assembly.GetExecutingAssembly().Location;
|
||||
return StartElevated(executablePath, string.Format("Hostsfile /ah+ /h:{0} /i:{1}", hostname, ipAddress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ipAddress"></param>
|
||||
/// <param name="hostname"></param>
|
||||
/// <returns></returns>
|
||||
public static int RemoveHostEntry(string ipAddress, string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetHostsEntry(false, ipAddress, hostname);
|
||||
return 0;
|
||||
}
|
||||
// ReSharper disable EmptyGeneralCatchClause
|
||||
catch
|
||||
// ReSharper restore EmptyGeneralCatchClause
|
||||
{
|
||||
}
|
||||
string executablePath = Assembly.GetExecutingAssembly().Location;
|
||||
return StartElevated(executablePath, string.Format("Hostsfile /ah- /h:{0} /i:{1}", hostname, ipAddress));
|
||||
}
|
||||
|
||||
private static void SetHostsEntry(bool addHost, string ipAddress, string hostname)
|
||||
{
|
||||
// limitation: while windows allows mulitple entries for a single host, we currently allow only one
|
||||
string windir = Environment.GetEnvironmentVariable("SystemRoot") ?? @"c:\windows";
|
||||
string hostsFilePath = Path.Combine(windir, @"system32\drivers\etc\hosts");
|
||||
|
||||
string hostsFileContent = File.ReadAllText(hostsFilePath);
|
||||
|
||||
hostsFileContent = Regex.Replace(hostsFileContent,
|
||||
string.Format(@"\r\n^\s*[\d\w\.:]+\s{0}\s#\sadded\sby\scassini$",
|
||||
hostname), "", RegexOptions.Multiline);
|
||||
|
||||
if (addHost)
|
||||
{
|
||||
hostsFileContent += string.Format("\r\n{0} {1} # added by cassini", ipAddress, hostname);
|
||||
}
|
||||
|
||||
File.WriteAllText(hostsFilePath, hostsFileContent);
|
||||
}
|
||||
|
||||
private static int StartElevated(string filename, string args)
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
WorkingDirectory = Environment.CurrentDirectory,
|
||||
FileName = filename,
|
||||
Arguments = args,
|
||||
Verb = "runas"
|
||||
};
|
||||
try
|
||||
{
|
||||
Process p = Process.Start(startInfo);
|
||||
if (p != null)
|
||||
{
|
||||
p.WaitForExit();
|
||||
return p.ExitCode;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="WebdevDirListing" xml:space="preserve">
|
||||
<value>Directory Listing -- {0}</value>
|
||||
</data>
|
||||
<data name="WebdevVwdName" xml:space="preserve">
|
||||
<value>CassiniDev Server</value>
|
||||
</data>
|
||||
<data name="WebdevServerError" xml:space="preserve">
|
||||
<value>Server Error in '{0}' Application.</value>
|
||||
</data>
|
||||
<data name="WebdevVersionInfo" xml:space="preserve">
|
||||
<value>Version Information</value>
|
||||
</data>
|
||||
<data name="WebdevHttpError" xml:space="preserve">
|
||||
<value>HTTP Error {0} - {1}.</value>
|
||||
</data>
|
||||
<data name="WebdevDirNotExist" xml:space="preserve">
|
||||
<value>The directory '{0}' does not exist.</value>
|
||||
</data>
|
||||
<data name="WebdevErrorListeningPort" xml:space="preserve">
|
||||
<value>CassiniDev Server failed to start listening on port {0}.
|
||||
Error message:
|
||||
{1}</value>
|
||||
</data>
|
||||
<data name="WebdevInvalidPort" xml:space="preserve">
|
||||
<value>Invalid port'{0}'</value>
|
||||
</data>
|
||||
<data name="WebdevName" xml:space="preserve">
|
||||
<value>CassiniDev Server</value>
|
||||
</data>
|
||||
<data name="WebdevNameWithPort" xml:space="preserve">
|
||||
<value>CassiniDev Server - Port {0}</value>
|
||||
</data>
|
||||
<data name="WebdevOpenInBrowser" xml:space="preserve">
|
||||
<value>Open in Web Browser</value>
|
||||
</data>
|
||||
<data name="WebdevRunAspNetLocally" xml:space="preserve">
|
||||
<value>Run ASP.NET applications locally.</value>
|
||||
</data>
|
||||
<data name="WebdevShowDetail" xml:space="preserve">
|
||||
<value>Show Details</value>
|
||||
</data>
|
||||
<data name="WebdevStop" xml:space="preserve">
|
||||
<value>Stop</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr1" xml:space="preserve">
|
||||
<value>CassiniDev Server Usage:
|
||||
</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr2" xml:space="preserve">
|
||||
<value>WebDev.WebServer /port:<port number> /path:<physical path> [/vpath:<virtual path>]
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr3" xml:space="preserve">
|
||||
<value> port number:
|
||||
[Optional] An unused port number between 1 and 65535.
|
||||
The default is 80 (usable if you do not also have IIS listening on the same port).
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr4" xml:space="preserve">
|
||||
<value> physical path:
|
||||
A valid directory name where the Web application is rooted.
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr5" xml:space="preserve">
|
||||
<value> virtual path:
|
||||
[Optional] The virtual path or application root in the form of '/<app name>'.
|
||||
The default is simply '/'.
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr6" xml:space="preserve">
|
||||
<value>Example:
|
||||
WebDev.WebServer /port:8080 /path:"c:\inetpub\wwwroot\MyApp" /vpath:"/MyApp"
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="WebdevUsagestr7" xml:space="preserve">
|
||||
<value>You can then access the Web application using a URL of the form:
|
||||
http://localhost:8080/MyApp</value>
|
||||
</data>
|
||||
<data name="WebdevLogViewerNameWithPort" xml:space="preserve">
|
||||
<value>CassiniDev Server - Port {0} - Log Viewer</value>
|
||||
</data>
|
||||
<data name="WebdevInMemoryLogging" xml:space="preserve">
|
||||
<value>In memory logging is enabled.
|
||||
|
||||
Events are only captured when the Log window is visible
|
||||
and all data will be lost when this window is closed.
|
||||
|
||||
Install the latest System.Data.SQLite package to enable
|
||||
log persistence.</value>
|
||||
</data>
|
||||
<data name="WebdevAspNetVersion" xml:space="preserve">
|
||||
<value>ASP.Net Version: {0}</value>
|
||||
</data>
|
||||
<data name="WebdevStart" xml:space="preserve">
|
||||
<value>Start</value>
|
||||
</data>
|
||||
<data name="ErrApplicationPathIsNull" xml:space="preserve">
|
||||
<value>ApplicationPath is null</value>
|
||||
</data>
|
||||
<data name="ErrFailedToStartCassiniDevServerOnPortError" xml:space="preserve">
|
||||
<value>Failed to start CassiniDev Server on Port:{0} Error:{1} {2}</value>
|
||||
</data>
|
||||
<data name="ErrInvalidHostname" xml:space="preserve">
|
||||
<value>Invalid Hostname {0}</value>
|
||||
</data>
|
||||
<data name="ErrInvalidIPAddress" xml:space="preserve">
|
||||
<value>Invalid IP Address {0}</value>
|
||||
</data>
|
||||
<data name="ErrInvalidIPMode" xml:space="preserve">
|
||||
<value>Invalid IPMode {0}</value>
|
||||
</data>
|
||||
<data name="ErrInvalidPortMode" xml:space="preserve">
|
||||
<value>Invalid PortMode</value>
|
||||
</data>
|
||||
<data name="ErrInvalidPortRangeValue" xml:space="preserve">
|
||||
<value>Invalid port range value {0}</value>
|
||||
</data>
|
||||
<data name="ErrNoAvailablePortFound" xml:space="preserve">
|
||||
<value>No available port found.</value>
|
||||
</data>
|
||||
<data name="ErrPortIsInUse" xml:space="preserve">
|
||||
<value>Port is in use {0}</value>
|
||||
</data>
|
||||
<data name="ErrPortOutOfRange" xml:space="preserve">
|
||||
<value>Port out of range: {0}</value>
|
||||
</data>
|
||||
<data name="ErrPortRangeEndMustBeEqualOrGreaterThanPortRangeSta" xml:space="preserve">
|
||||
<value>Port range end must be equal or greater than port range start {0} {1}</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,164 @@
|
||||
// **********************************************************************************
|
||||
// CassiniDev - http://cassinidev.codeplex.com
|
||||
//
|
||||
// Copyright (c) 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.htm file
|
||||
// included in this distribution.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
//
|
||||
// **********************************************************************************
|
||||
|
||||
#region
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Threading;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
internal sealed class SR
|
||||
{
|
||||
|
||||
internal const string ErrInvalidIPMode="SR.ErrInvalidIPMode";
|
||||
internal const string ErrInvalidIPAddress = "ErrInvalidIPAddress";
|
||||
internal const string ErrInvalidPortMode = "ErrInvalidPortMode";
|
||||
internal const string ErrPortIsInUse = "ErrPortIsInUse";
|
||||
internal const string ErrNoAvailablePortFound = "ErrNoAvailablePortFound";
|
||||
internal const string ErrPortRangeEndMustBeEqualOrGreaterThanPortRangeSta =
|
||||
"ErrPortRangeEndMustBeEqualOrGreaterThanPortRangeSta";
|
||||
internal const string ErrInvalidPortRangeValue = "ErrInvalidPortRangeValue";
|
||||
internal const string ErrInvalidHostname = "ErrInvalidHostname";
|
||||
|
||||
internal const string ErrFailedToStartCassiniDevServerOnPortError =
|
||||
"ErrFailedToStartCassiniDevServerOnPortError";
|
||||
internal const string ErrApplicationPathIsNull = "ErrApplicationPathIsNull";
|
||||
internal const string ErrPortOutOfRange = "ErrPortOutOfRange";
|
||||
|
||||
internal const string WebdevAspNetVersion = "WebdevAspNetVersion";
|
||||
|
||||
internal const string WebdevDirListing = "WebdevDirListing";
|
||||
|
||||
internal const string WebdevDirNotExist = "WebdevDirNotExist";
|
||||
|
||||
internal const string WebdevErrorListeningPort = "WebdevErrorListeningPort";
|
||||
|
||||
internal const string WebdevHttpError = "WebdevHttpError";
|
||||
|
||||
internal const string WebdevInMemoryLogging = "WebdevInMemoryLogging";
|
||||
|
||||
internal const string WebdevInvalidPort = "WebdevInvalidPort";
|
||||
|
||||
internal const string WebdevLogViewerNameWithPort = "WebdevLogViewerNameWithPort";
|
||||
|
||||
internal const string WebdevName = "WebdevName";
|
||||
|
||||
internal const string WebdevNameWithPort = "WebdevNameWithPort";
|
||||
|
||||
internal const string WebdevOpenInBrowser = "WebdevOpenInBrowser";
|
||||
|
||||
internal const string WebdevRunAspNetLocally = "WebdevRunAspNetLocally";
|
||||
|
||||
internal const string WebdevServerError = "WebdevServerError";
|
||||
|
||||
internal const string WebdevShowDetail = "WebdevShowDetail";
|
||||
|
||||
internal const string WebdevStop = "WebdevStop";
|
||||
|
||||
internal const string WebdevUsagestr1 = "WebdevUsagestr1";
|
||||
|
||||
internal const string WebdevUsagestr2 = "WebdevUsagestr2";
|
||||
|
||||
internal const string WebdevUsagestr3 = "WebdevUsagestr3";
|
||||
|
||||
internal const string WebdevUsagestr4 = "WebdevUsagestr4";
|
||||
|
||||
internal const string WebdevUsagestr5 = "WebdevUsagestr5";
|
||||
|
||||
internal const string WebdevUsagestr6 = "WebdevUsagestr6";
|
||||
|
||||
internal const string WebdevUsagestr7 = "WebdevUsagestr7";
|
||||
|
||||
internal const string WebdevVersionInfo = "WebdevVersionInfo";
|
||||
|
||||
internal const string WebdevVwdName = "WebdevVwdName";
|
||||
|
||||
private static SR _loader;
|
||||
|
||||
private readonly ResourceManager _resources;
|
||||
public const string WebdevStart = "WebdevStart";
|
||||
|
||||
internal SR()
|
||||
{
|
||||
Type t = GetType();
|
||||
Assembly thisAssembly = t.Assembly;
|
||||
string stringResourcesName = t.Namespace + ".Resources.CassiniDev";
|
||||
_resources = new ResourceManager(stringResourcesName, thisAssembly);
|
||||
}
|
||||
|
||||
private static CultureInfo Culture
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public static ResourceManager Resources
|
||||
{
|
||||
get { return GetLoader()._resources; }
|
||||
}
|
||||
|
||||
public static string GetString(string name)
|
||||
{
|
||||
SR loader = GetLoader();
|
||||
if (loader == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return loader._resources.GetString(name, Culture);
|
||||
}
|
||||
|
||||
public static string GetString(string name, params object[] args)
|
||||
{
|
||||
SR loader = GetLoader();
|
||||
if (loader == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string format = loader._resources.GetString(name, Culture);
|
||||
if ((args == null) || (args.Length <= 0))
|
||||
{
|
||||
return format;
|
||||
}
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
string str2 = args[i] as string;
|
||||
if ((str2 != null) && (str2.Length > 0x400))
|
||||
{
|
||||
args[i] = str2.Substring(0, 0x3fd) + "...";
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return string.Format(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
private static SR GetLoader()
|
||||
{
|
||||
if (_loader == null)
|
||||
{
|
||||
SR sr = new SR();
|
||||
Interlocked.CompareExchange(ref _loader, sr, null);
|
||||
}
|
||||
return _loader;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
@ -0,0 +1,834 @@
|
||||
// **********************************************************************************
|
||||
// CassiniDev - http://cassinidev.codeplex.com
|
||||
//
|
||||
// Copyright (c) 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.htm 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.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using CassiniDev.ServerLog;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CassiniDev
|
||||
{
|
||||
public partial class FormView : Form
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private bool _automated;
|
||||
|
||||
private LogView _logForm;
|
||||
|
||||
private RunState _runState;
|
||||
|
||||
private Server _server;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public FormView(Server server)
|
||||
{
|
||||
_server = server;
|
||||
InitializeComponent();
|
||||
InitializeUI();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
internal bool AddHost
|
||||
{
|
||||
get { return AddHostEntryCheckBox.Checked; }
|
||||
set { AddHostEntryCheckBox.Checked = value; }
|
||||
}
|
||||
|
||||
internal string ApplicationPath
|
||||
{
|
||||
get { return ApplicationPathTextBox.Text; }
|
||||
set { ApplicationPathTextBox.Text = value; }
|
||||
}
|
||||
|
||||
internal string HostName
|
||||
{
|
||||
get { return HostNameTextBox.Text; }
|
||||
set { HostNameTextBox.Text = value; }
|
||||
}
|
||||
|
||||
internal string IPAddress
|
||||
{
|
||||
get { return IPSpecificTextBox.Text; }
|
||||
set { IPSpecificTextBox.Text = value; }
|
||||
}
|
||||
|
||||
internal IPMode IPMode
|
||||
{
|
||||
get { return GetIpMode(); }
|
||||
set { SetIpMode(value); }
|
||||
}
|
||||
|
||||
|
||||
internal bool NoDirList
|
||||
{
|
||||
get { return !directoryBrowsingEnabledToolStripMenuItem.Checked; }
|
||||
set { directoryBrowsingEnabledToolStripMenuItem.Checked = !value; }
|
||||
}
|
||||
|
||||
internal bool NtmlAuthenticationRequired
|
||||
{
|
||||
get { return nTLMAuthenticationRequiredToolStripMenuItem.Checked; }
|
||||
set { nTLMAuthenticationRequiredToolStripMenuItem.Checked = value; }
|
||||
}
|
||||
|
||||
internal int Port
|
||||
{
|
||||
get { return (int)PortTextBox.Value; }
|
||||
set { PortTextBox.Value = value; }
|
||||
}
|
||||
|
||||
internal PortMode PortMode
|
||||
{
|
||||
get { return GetPortMode(); }
|
||||
set { SetPortMode(value); }
|
||||
}
|
||||
|
||||
internal int PortRangeEnd
|
||||
{
|
||||
get { return (int)PortRangeEndTextBox.Value; }
|
||||
set { PortRangeEndTextBox.Value = value; }
|
||||
}
|
||||
|
||||
internal int PortRangeStart
|
||||
{
|
||||
get { return (int)PortRangeStartTextBox.Value; }
|
||||
set { PortRangeStartTextBox.Value = value; }
|
||||
}
|
||||
|
||||
internal string RootUrl
|
||||
{
|
||||
get { return RootUrlLinkLabel.Text; }
|
||||
set
|
||||
{
|
||||
RootUrlLinkLabel.Text = value;
|
||||
RootUrlLinkLabel.Visible = !string.IsNullOrEmpty(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal RunState RunState
|
||||
{
|
||||
get { return _runState; }
|
||||
}
|
||||
|
||||
internal int TimeOut
|
||||
{
|
||||
get { return (int)TimeOutNumeric.Value; }
|
||||
set { TimeOutNumeric.Value = value; }
|
||||
}
|
||||
|
||||
internal bool V6
|
||||
{
|
||||
get { return IPV6CheckBox.Checked; }
|
||||
set { IPV6CheckBox.Checked = value; }
|
||||
}
|
||||
|
||||
internal string VirtualPath
|
||||
{
|
||||
get { return VirtualPathTextBox.Text; }
|
||||
set { VirtualPathTextBox.Text = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
|
||||
if (disposing && _server != null)
|
||||
{
|
||||
_server.Dispose();
|
||||
_server = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the form is closing we need to determine whether to exit
|
||||
/// or to minimize to tray.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
// if explicit closure or we are doing nothing then exit app.
|
||||
if (RunState == RunState.Idle)
|
||||
{
|
||||
InvokeStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = FormWindowState.Minimized;
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
//protected override void OnShown(EventArgs e)
|
||||
//{
|
||||
// if (_automated)
|
||||
// {
|
||||
// WindowState = FormWindowState.Minimized;
|
||||
// Hide();
|
||||
// }
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
|
||||
private void InitializeUI()
|
||||
{
|
||||
ButtonStart.Text = SR.GetString(SR.WebdevStart);
|
||||
toolStripStatusLabel1.Text = SR.GetString(SR.WebdevAspNetVersion, Common.GetAspVersion());
|
||||
|
||||
|
||||
// if sqlite is missing then just silently enable in-memory logging,
|
||||
// hide the enable logging item and enable view log item
|
||||
|
||||
|
||||
|
||||
ShowLogButton.Enabled = false;
|
||||
|
||||
|
||||
|
||||
toolStripStatusLabel1.Text = SR.GetString(SR.WebdevAspNetVersion, Common.GetAspVersion());
|
||||
|
||||
List<IPAddress> localAddresses = new List<IPAddress>(CassiniNetworkUtils.GetLocalAddresses());
|
||||
localAddresses.Insert(0, System.Net.IPAddress.IPv6Loopback);
|
||||
localAddresses.Insert(0, System.Net.IPAddress.Loopback);
|
||||
|
||||
IPSpecificTextBox.Items.AddRange(localAddresses.Select(i => i.ToString()).ToArray());
|
||||
if (IPSpecificTextBox.Items.Count > 0)
|
||||
{
|
||||
IPSpecificTextBox.SelectedIndex = 0;
|
||||
IPSpecificTextBox.Text = IPSpecificTextBox.Items[0].ToString();
|
||||
}
|
||||
|
||||
InvokeSetRunState(RunState.Idle);
|
||||
if (_server == null)
|
||||
{
|
||||
ShowMainForm();
|
||||
}
|
||||
else
|
||||
{
|
||||
_automated = true;
|
||||
_server.TimedOut += OnTimedOut;
|
||||
IPMode = IPMode.Specific;
|
||||
PortMode = PortMode.Specific;
|
||||
|
||||
UpdateUIFromServer();
|
||||
|
||||
|
||||
InvokeSetRunState(RunState.Running);
|
||||
base.Text = SR.GetString(SR.WebdevNameWithPort, _server.Port);
|
||||
TrayIcon.Visible = true;
|
||||
DisplayTrayTip();
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayTrayTip()
|
||||
{
|
||||
|
||||
if (_server==null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TrayIcon.Text = _server.RootUrl;
|
||||
string trayBaloonText = _server.RootUrl;
|
||||
TrayIcon.ShowBalloonTip(5000, base.Text, trayBaloonText, ToolTipIcon.Info);
|
||||
}
|
||||
|
||||
private void UpdateUIFromServer()
|
||||
{
|
||||
base.Text = SR.GetString(SR.WebdevNameWithPort, _server.Port);
|
||||
RootUrl = _server.RootUrl;
|
||||
ApplicationPath = _server.PhysicalPath;
|
||||
IPAddress = _server.IPAddress.ToString();
|
||||
Port = _server.Port;
|
||||
HostName = _server.HostName;
|
||||
NtmlAuthenticationRequired = _server.RequireAuthentication;
|
||||
NoDirList = _server.DisableDirectoryListing;
|
||||
TimeOut = _server.TimeoutInterval;
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
if (WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
Hide();
|
||||
DisplayTrayTip();
|
||||
ShowInTaskbar = false;
|
||||
}
|
||||
base.OnResize(e);
|
||||
}
|
||||
|
||||
|
||||
private void ShowMainForm()
|
||||
{
|
||||
Show();
|
||||
WindowState = FormWindowState.Normal;
|
||||
ShowInTaskbar = true;
|
||||
|
||||
|
||||
//TrayIcon.Visible = false;
|
||||
//ShowInTaskbar = true;
|
||||
|
||||
//TopMost = true;
|
||||
//Focus();
|
||||
//BringToFront();
|
||||
//TopMost = false;
|
||||
}
|
||||
|
||||
private void InvokeSetRunState(RunState state)
|
||||
{
|
||||
// use invoke, runstate may come from another thread.
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(new ParameterizedThreadStart(SetRunState), state);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRunState(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets RunState and enables/disables form fields accordingly
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
private void SetRunState(object state)
|
||||
{
|
||||
_runState = (RunState)state;
|
||||
|
||||
switch (_runState)
|
||||
{
|
||||
case RunState.Idle:
|
||||
if (!_automated)
|
||||
{
|
||||
EnableForm();
|
||||
}
|
||||
// if not automated we are on our way out
|
||||
break;
|
||||
case RunState.Running:
|
||||
DisableForm();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void EnableForm()
|
||||
{
|
||||
ShowLogMenuItem.Enabled = ShowLogButton.Enabled = false;
|
||||
base.Text = SR.GetString(SR.WebdevName);
|
||||
ButtonStart.Text = "&Start";
|
||||
ButtonStart.Enabled = true;
|
||||
nTLMAuthenticationRequiredToolStripMenuItem.Enabled = true;
|
||||
directoryBrowsingEnabledToolStripMenuItem.Enabled = true;
|
||||
ApplicationPathTextBox.Enabled = true;
|
||||
ButtonBrowsePhysicalPath.Enabled = true;
|
||||
VirtualPathTextBox.Enabled = true;
|
||||
HostNameTextBox.Enabled = true;
|
||||
GroupBoxIPAddress.Enabled = true;
|
||||
GroupBoxPort.Enabled = true;
|
||||
LabelHostName.Enabled = true;
|
||||
LabelPhysicalPath.Enabled = true;
|
||||
LabelVPath.Enabled = true;
|
||||
TimeOutNumeric.Enabled = true;
|
||||
RootUrl = null;
|
||||
|
||||
AddHostEntryCheckBox.Enabled = !String.IsNullOrEmpty(HostName);
|
||||
|
||||
switch (IPMode)
|
||||
{
|
||||
case IPMode.Loopback:
|
||||
RadioButtonIPLoopBack_CheckedChanged(null, EventArgs.Empty);
|
||||
break;
|
||||
case IPMode.Any:
|
||||
RadioButtonIPAny_CheckedChanged(null, EventArgs.Empty);
|
||||
break;
|
||||
case IPMode.Specific:
|
||||
RadioButtonIPSpecific_CheckedChanged(null, EventArgs.Empty);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (PortMode)
|
||||
{
|
||||
case PortMode.FirstAvailable:
|
||||
RadioButtonPortFind_CheckedChanged(null, EventArgs.Empty);
|
||||
break;
|
||||
case PortMode.Specific:
|
||||
RadioButtonPortSpecific_CheckedChanged(null, EventArgs.Empty);
|
||||
break;
|
||||
}
|
||||
|
||||
HostNameChanged(null, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void DisableForm()
|
||||
{
|
||||
ShowLogMenuItem.Enabled = ShowLogButton.Enabled = true;
|
||||
|
||||
TimeOutNumeric.Enabled = false;
|
||||
ButtonStart.Text = "&Stop";
|
||||
directoryBrowsingEnabledToolStripMenuItem.Enabled = false;
|
||||
nTLMAuthenticationRequiredToolStripMenuItem.Enabled = false;
|
||||
ApplicationPathTextBox.Enabled = false;
|
||||
ButtonBrowsePhysicalPath.Enabled = false;
|
||||
VirtualPathTextBox.Enabled = false;
|
||||
HostNameTextBox.Enabled = false;
|
||||
GroupBoxIPAddress.Enabled = false;
|
||||
GroupBoxPort.Enabled = false;
|
||||
AddHostEntryCheckBox.Enabled = false;
|
||||
LabelHostName.Enabled = false;
|
||||
LabelPhysicalPath.Enabled = false;
|
||||
LabelVPath.Enabled = false;
|
||||
}
|
||||
|
||||
private void HostNameChanged()
|
||||
{
|
||||
if (string.IsNullOrEmpty(HostName))
|
||||
{
|
||||
AddHostEntryCheckBox.Enabled = false;
|
||||
AddHost = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHostEntryCheckBox.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StartStop()
|
||||
{
|
||||
if (RunState != RunState.Running)
|
||||
{
|
||||
DisableForm();
|
||||
Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
InvokeStop();
|
||||
}
|
||||
}
|
||||
|
||||
private CommandLineArguments GetArgs()
|
||||
{
|
||||
CommandLineArguments args = new CommandLineArguments
|
||||
{
|
||||
AddHost = AddHost,
|
||||
ApplicationPath = ApplicationPath,
|
||||
HostName = HostName,
|
||||
IPAddress = IPAddress,
|
||||
IPMode = IPMode,
|
||||
IPv6 = V6,
|
||||
Port = Port,
|
||||
PortMode = PortMode,
|
||||
PortRangeEnd = PortRangeEnd,
|
||||
PortRangeStart = PortRangeStart,
|
||||
VirtualPath = VirtualPath,
|
||||
TimeOut = TimeOut,
|
||||
WaitForPort = 0,
|
||||
Ntlm = NtmlAuthenticationRequired,
|
||||
Nodirlist = NoDirList
|
||||
};
|
||||
return args;
|
||||
}
|
||||
private void Start()
|
||||
{
|
||||
// use CommandLineArguments as a pre validation tool
|
||||
|
||||
CommandLineArguments args = GetArgs();
|
||||
ClearError();
|
||||
|
||||
try
|
||||
{
|
||||
args.Validate();
|
||||
}
|
||||
|
||||
catch (CassiniException ex)
|
||||
{
|
||||
SetError(ex.Field, ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
IPAddress = args.IPAddress;
|
||||
|
||||
Port = args.Port;
|
||||
|
||||
HostName = args.HostName;
|
||||
|
||||
_server = new Server(args.Port, args.VirtualPath, args.ApplicationPath,
|
||||
System.Net.IPAddress.Parse(args.IPAddress), args.HostName, args.TimeOut, args.Ntlm,
|
||||
args.Nodirlist);
|
||||
|
||||
if (args.AddHost)
|
||||
{
|
||||
HostsFile.AddHostEntry(_server.IPAddress.ToString(), _server.HostName);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_server.Start();
|
||||
_server.TimedOut += OnTimedOut;
|
||||
UpdateUIFromServer();
|
||||
InvokeSetRunState(RunState.Running);
|
||||
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
SetError(ErrorField.None, ex.Message);
|
||||
_server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The server could be stopped either by user action,
|
||||
/// timeout or exception. If by timeout, the call will be
|
||||
/// coming from another thread in another appdomain far far
|
||||
/// away, so we execise caution and wrap the method that
|
||||
/// actual does the stoppage in this invokable wrapper.
|
||||
/// </summary>
|
||||
private void InvokeStop()
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(new MethodInvoker(Stop));
|
||||
}
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void Stop()
|
||||
{
|
||||
// kill the start button so we don't get a start
|
||||
// signal before completely stopped.
|
||||
ButtonStart.Enabled = false;
|
||||
|
||||
// revert the host file modification, if necessary
|
||||
if (AddHost && RunState == RunState.Running)
|
||||
{
|
||||
HostsFile.RemoveHostEntry(_server.IPAddress.ToString(), _server.HostName);
|
||||
}
|
||||
|
||||
if (_server != null)
|
||||
{
|
||||
_server.TimedOut -= OnTimedOut;
|
||||
_server.Dispose();
|
||||
}
|
||||
|
||||
RootUrl = string.Empty;
|
||||
|
||||
InvokeSetRunState(RunState.Idle);
|
||||
|
||||
if (_automated)
|
||||
{
|
||||
ExitApp();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void ExitApp()
|
||||
{
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
|
||||
private static void ShowHelp()
|
||||
{
|
||||
MessageBox.Show("help/about TODO");
|
||||
}
|
||||
|
||||
private void ShowLog()
|
||||
{
|
||||
if (_logForm == null || _logForm.IsDisposed)
|
||||
{
|
||||
_logForm = new LogView(_server);
|
||||
}
|
||||
_logForm.Show();
|
||||
_logForm.BringToFront();
|
||||
}
|
||||
|
||||
|
||||
private void BrowsePath()
|
||||
{
|
||||
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
||||
|
||||
if (fbd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
ApplicationPath = fbd.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchBrowser()
|
||||
{
|
||||
Process.Start(RootUrlLinkLabel.Text);
|
||||
}
|
||||
|
||||
|
||||
private IPMode GetIpMode()
|
||||
{
|
||||
IPMode result;
|
||||
if (IPModeAnyRadioButton.Checked)
|
||||
{
|
||||
result = IPMode.Any;
|
||||
}
|
||||
else if (IPModeLoopBackRadioButton.Checked)
|
||||
{
|
||||
result = IPMode.Loopback;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = IPMode.Specific;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private PortMode GetPortMode()
|
||||
{
|
||||
return PortModeSpecificRadioButton.Checked ? PortMode.Specific : PortMode.FirstAvailable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void SetIpMode(IPMode value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case IPMode.Loopback:
|
||||
IPModeLoopBackRadioButton.Checked = true;
|
||||
break;
|
||||
case IPMode.Any:
|
||||
IPModeAnyRadioButton.Checked = true;
|
||||
break;
|
||||
case IPMode.Specific:
|
||||
RadioButtonIPSpecific.Checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPortMode(PortMode value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case PortMode.FirstAvailable:
|
||||
PortModeFirstAvailableRadioButton.Checked = true;
|
||||
break;
|
||||
case PortMode.Specific:
|
||||
PortModeSpecificRadioButton.Checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void SetError(ErrorField field, string value)
|
||||
{
|
||||
EnableForm();
|
||||
switch (field)
|
||||
{
|
||||
case ErrorField.ApplicationPath:
|
||||
errorProvider1.SetError(ApplicationPathTextBox, value);
|
||||
break;
|
||||
case ErrorField.VirtualPath:
|
||||
errorProvider1.SetError(VirtualPathTextBox, value);
|
||||
break;
|
||||
case ErrorField.HostName:
|
||||
errorProvider1.SetError(HostNameTextBox, value);
|
||||
break;
|
||||
case ErrorField.IsAddHost:
|
||||
errorProvider1.SetError(AddHostEntryCheckBox, value);
|
||||
break;
|
||||
case ErrorField.IPAddress:
|
||||
errorProvider1.SetError(IPSpecificTextBox, value);
|
||||
break;
|
||||
case ErrorField.IPAddressAny:
|
||||
errorProvider1.SetError(IPModeAnyRadioButton, value);
|
||||
break;
|
||||
case ErrorField.IPAddressLoopBack:
|
||||
errorProvider1.SetError(IPModeLoopBackRadioButton, value);
|
||||
break;
|
||||
case ErrorField.Port:
|
||||
errorProvider1.SetError(PortTextBox, value);
|
||||
break;
|
||||
case ErrorField.PortRange:
|
||||
errorProvider1.SetError(PortRangeStartTextBox, value);
|
||||
errorProvider1.SetError(PortRangeEndTextBox, value);
|
||||
break;
|
||||
case ErrorField.PortRangeStart:
|
||||
errorProvider1.SetError(PortRangeStartTextBox, value);
|
||||
break;
|
||||
case ErrorField.PortRangeEnd:
|
||||
errorProvider1.SetError(PortRangeEndTextBox, value);
|
||||
break;
|
||||
case ErrorField.None:
|
||||
MessageBox.Show(value, "Error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearError()
|
||||
{
|
||||
errorProvider1.Clear();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Handlers
|
||||
|
||||
private void BrowsePath(object sender, EventArgs e)
|
||||
{
|
||||
BrowsePath();
|
||||
}
|
||||
|
||||
private void HideMainForm(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void LaunchBrowser(object sender, EventArgs e)
|
||||
{
|
||||
LaunchBrowser();
|
||||
}
|
||||
|
||||
private void LaunchBrowser(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
LaunchBrowser();
|
||||
}
|
||||
|
||||
private void ShowHelp(object sender, EventArgs e)
|
||||
{
|
||||
ShowHelp();
|
||||
}
|
||||
|
||||
private void ShowLog(object sender, EventArgs e)
|
||||
{
|
||||
ShowLog();
|
||||
}
|
||||
|
||||
private void ShowMainForm(object sender, EventArgs e)
|
||||
{
|
||||
ShowMainForm();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Responds to the Start/Stop button
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void StartStop(object sender, EventArgs e)
|
||||
{
|
||||
StartStop();
|
||||
}
|
||||
|
||||
|
||||
private void ExitApp(object sender, EventArgs e)
|
||||
{
|
||||
ExitApp();
|
||||
}
|
||||
|
||||
private void HostNameChanged(object sender, EventArgs e)
|
||||
{
|
||||
HostNameChanged();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// If a timeout value is specifically set and we
|
||||
/// get a timeout event, just exit the application.
|
||||
/// This should always be the case, but will be
|
||||
/// a bit forgiving here and perform a check before
|
||||
/// dumping.
|
||||
/// </summary>
|
||||
private void OnTimedOut(object sender, EventArgs e)
|
||||
{
|
||||
InvokeStop();
|
||||
|
||||
if (TimeOut > 0)
|
||||
{
|
||||
ExitApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowMainForm();
|
||||
}
|
||||
}
|
||||
|
||||
#region Hinky lookin radios that depend on known state. Could be a source of trouble.
|
||||
|
||||
private void RadioButtonIPAny_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
IPSpecificTextBox.Enabled = false;
|
||||
IPV6CheckBox.Enabled = true;
|
||||
}
|
||||
|
||||
private void RadioButtonIPLoopBack_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
IPSpecificTextBox.Enabled = false;
|
||||
IPV6CheckBox.Enabled = true;
|
||||
}
|
||||
|
||||
private void RadioButtonIPSpecific_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
IPSpecificTextBox.Enabled = true;
|
||||
IPV6CheckBox.Enabled = false;
|
||||
IPV6CheckBox.Checked = false;
|
||||
}
|
||||
|
||||
private void RadioButtonPortFind_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
PortTextBox.Enabled = false;
|
||||
PortRangeEndTextBox.Enabled = true;
|
||||
PortRangeStartTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
private void RadioButtonPortSpecific_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
PortTextBox.Enabled = true;
|
||||
PortRangeEndTextBox.Enabled = false;
|
||||
PortRangeStartTextBox.Enabled = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,290 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>147, 17</value>
|
||||
</metadata>
|
||||
<data name="HostNameTextBox.ToolTip" xml:space="preserve">
|
||||
<value>The host name to use in place of 'localhost'.
|
||||
This value must be a valid DNS host name or be present in the local hosts file.
|
||||
You may check 'Add hosts entry' to add such an entry to the hosts file for the duration of the hosting session.
|
||||
Adding a hosts entry requires elevated permissions, both upon adding and again upon removal.</value>
|
||||
</data>
|
||||
<data name="AddHostEntryCheckBox.ToolTip" xml:space="preserve">
|
||||
<value>You may check 'Add hosts entry' to add such an entry to the hosts file for the duration of the hosting session.
|
||||
Adding a hosts entry requires elevated permissions, both upon adding and again upon removal.</value>
|
||||
</data>
|
||||
<data name="LabelHostName.ToolTip" xml:space="preserve">
|
||||
<value>The host name to use in place of 'localhost'.
|
||||
This value must be a valid DNS host name or be present in the local hosts file.
|
||||
You may check 'Add hosts entry' to add such an entry to the hosts file for the duration of the hosting session.
|
||||
Adding a hosts entry requires elevated permissions, both upon adding and again upon removal.
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="errorProvider1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>696, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>586, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAEAMDAAAAAAAACoDgAAFgAAACgAAAAwAAAAYAAAAAEACAAAAAAAgAoAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAA////AA+V+QDGiDAAj7euAHsfFQDsxn4ATuv/AKrZ/gC7iH8AAeL+AJpRSQBJqs4Az8jEAHO+
|
||||
/gC3w4gA1axVAPnqygCNTRkAIMXvAK+BVQCVvtkAPqH8APTZpwDXsp8A0en9AK5mKQBpx78A06Z7AKqi
|
||||
kgBw3/4AqNXFAE/D/gC6wa4Ax5BjAIk1KwBiruMALJXkAAa4+ABDw9gAjs3/AKloXgDGm5MAcKu6AB3n
|
||||
/wDu7+4A6s5iALbS5gDOlkUAfs7oAKSVYACzb0QAo4Z1AJpLMQCeucEA4bdtAIHBxgC4xdAA48i5ANy2
|
||||
iQAhqukAVcHLAL2lfwCzemsAvoRNADLM/QCpgTsA6MqYACmY+wDw370At5dwAF2z/gCoXj0Aqq6kAAjN
|
||||
+QCPqaAAu3gvAMazlAC+4v8Au5pOANDBogCjVSQAkTodAGLZ/wCV3P4Au6WgAJLJogCqxaEA1KZqAHiz
|
||||
1wCgb1IAr6+UAGXo/wDFk30AycSHAHfN+wDUqYsAqcrYAES95QCF2f4AhSwfADjK5gCOxOYAyrV+ALGa
|
||||
fAC7flkAosCzAGbH/wCRucAAFLf0AJNHPQDCztsAvIZtAF682ADawnUAsohkAKJcTwDH3/IA1KBQAMa7
|
||||
ogCZsKoAoWo+APfgrQC4u78A8tWaAMmSUQDLpJwAmEUhAI09MACSzN4A0Jk6AK5vWQCw1/IAy5huANW/
|
||||
lwDpwHMAzbBlABjL9ADbvKsAhsT0AKV6bgCod10Asod2ALavqQDqx4cA2K96AKRXLwDIjjwAwZGJAODE
|
||||
ngCbXDkAunpDAOW+ewDAhmAAcNT/ALJuMgCe0/8AhsS5AKOoogAluecAosrBAALY/QB/xf4AYsPNAMOo
|
||||
iwC3hVUAppmGADDD7QDgvJcADcD3AL6gdgCW2PQAiLfNAGzq/wC6s7QAorW3AKtlSgCaTkAAwoM3AKqD
|
||||
ZAC4d04A26xaAM+bWwDHqoIAbLa7AMuchQCsZDMA055IALzNhQC0gS8AV8XZAJ5RKQD45b8AZbn+AKVh
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAD////n//8AAP///8f//wAA///4A///
|
||||
AAD//8AB//8AAP//AAA//wAA//wAAB//AAD/8AAAB/8AAP/gAAAD/wAA/8AAAAD/AAD/gAAAAH8AAP8A
|
||||
AAAAfwAA/gAAAAA/AAD8AAAAAB8AAPwAAAAAHwAA+AAAAAAPAAD4AAAAAAcAAPAAAAAABwAA8AAAAAAH
|
||||
AADwAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAA
|
||||
AAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADwAAAAAAMAAPAAAAAABwAA8AAAAAAH
|
||||
AAD4AAAAAAcAAPgAAAAADwAA/AAAAAAfAAD8AAAAAB8AAP4AAAAAPwAA/wAAAAB/AAD/gAAAAP8AAP/A
|
||||
AAAB/wAA/+AAAAP/AAD/8AAAB/8AAP/8AAAH/wAA//8AAHf/AAD//+AB//8AAP///////wAA
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="TrayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>346, 17</value>
|
||||
</metadata>
|
||||
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>441, 17</value>
|
||||
</metadata>
|
||||
<data name="TrayIcon.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAEAMDAAAAAAAACoDgAAFgAAACgAAAAwAAAAYAAAAAEACAAAAAAAgAoAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAA////AA+V+QDGiDAAj7euAHsfFQDsxn4ATuv/AKrZ/gC7iH8AAeL+AJpRSQBJqs4Az8jEAHO+
|
||||
/gC3w4gA1axVAPnqygCNTRkAIMXvAK+BVQCVvtkAPqH8APTZpwDXsp8A0en9AK5mKQBpx78A06Z7AKqi
|
||||
kgBw3/4AqNXFAE/D/gC6wa4Ax5BjAIk1KwBiruMALJXkAAa4+ABDw9gAjs3/AKloXgDGm5MAcKu6AB3n
|
||||
/wDu7+4A6s5iALbS5gDOlkUAfs7oAKSVYACzb0QAo4Z1AJpLMQCeucEA4bdtAIHBxgC4xdAA48i5ANy2
|
||||
iQAhqukAVcHLAL2lfwCzemsAvoRNADLM/QCpgTsA6MqYACmY+wDw370At5dwAF2z/gCoXj0Aqq6kAAjN
|
||||
+QCPqaAAu3gvAMazlAC+4v8Au5pOANDBogCjVSQAkTodAGLZ/wCV3P4Au6WgAJLJogCqxaEA1KZqAHiz
|
||||
1wCgb1IAr6+UAGXo/wDFk30AycSHAHfN+wDUqYsAqcrYAES95QCF2f4AhSwfADjK5gCOxOYAyrV+ALGa
|
||||
fAC7flkAosCzAGbH/wCRucAAFLf0AJNHPQDCztsAvIZtAF682ADawnUAsohkAKJcTwDH3/IA1KBQAMa7
|
||||
ogCZsKoAoWo+APfgrQC4u78A8tWaAMmSUQDLpJwAmEUhAI09MACSzN4A0Jk6AK5vWQCw1/IAy5huANW/
|
||||
lwDpwHMAzbBlABjL9ADbvKsAhsT0AKV6bgCod10Asod2ALavqQDqx4cA2K96AKRXLwDIjjwAwZGJAODE
|
||||
ngCbXDkAunpDAOW+ewDAhmAAcNT/ALJuMgCe0/8AhsS5AKOoogAluecAosrBAALY/QB/xf4AYsPNAMOo
|
||||
iwC3hVUAppmGADDD7QDgvJcADcD3AL6gdgCW2PQAiLfNAGzq/wC6s7QAorW3AKtlSgCaTkAAwoM3AKqD
|
||||
ZAC4d04A26xaAM+bWwDHqoIAbLa7AMuchQCsZDMA055IALzNhQC0gS8AV8XZAJ5RKQD45b8AZbn+AKVh
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAD////n//8AAP///8f//wAA///4A///
|
||||
AAD//8AB//8AAP//AAA//wAA//wAAB//AAD/8AAAB/8AAP/gAAAD/wAA/8AAAAD/AAD/gAAAAH8AAP8A
|
||||
AAAAfwAA/gAAAAA/AAD8AAAAAB8AAPwAAAAAHwAA+AAAAAAPAAD4AAAAAAcAAPAAAAAABwAA8AAAAAAH
|
||||
AADwAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAA
|
||||
AAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADwAAAAAAMAAPAAAAAABwAA8AAAAAAH
|
||||
AAD4AAAAAAcAAPgAAAAADwAA/AAAAAAfAAD8AAAAAB8AAP4AAAAAPwAA/wAAAAB/AAD/gAAAAP8AAP/A
|
||||
AAAB/wAA/+AAAAP/AAD/8AAAB/8AAP/8AAAH/wAA//8AAHf/AAD//+AB//8AAP///////wAA
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>175, 17</value>
|
||||
</metadata>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>267, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAEAMDAAAAAAAACoDgAAFgAAACgAAAAwAAAAYAAAAAEACAAAAAAAgAoAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAA////AA+V+QDGiDAAj7euAHsfFQDsxn4ATuv/AKrZ/gC7iH8AAeL+AJpRSQBJqs4Az8jEAHO+
|
||||
/gC3w4gA1axVAPnqygCNTRkAIMXvAK+BVQCVvtkAPqH8APTZpwDXsp8A0en9AK5mKQBpx78A06Z7AKqi
|
||||
kgBw3/4AqNXFAE/D/gC6wa4Ax5BjAIk1KwBiruMALJXkAAa4+ABDw9gAjs3/AKloXgDGm5MAcKu6AB3n
|
||||
/wDu7+4A6s5iALbS5gDOlkUAfs7oAKSVYACzb0QAo4Z1AJpLMQCeucEA4bdtAIHBxgC4xdAA48i5ANy2
|
||||
iQAhqukAVcHLAL2lfwCzemsAvoRNADLM/QCpgTsA6MqYACmY+wDw370At5dwAF2z/gCoXj0Aqq6kAAjN
|
||||
+QCPqaAAu3gvAMazlAC+4v8Au5pOANDBogCjVSQAkTodAGLZ/wCV3P4Au6WgAJLJogCqxaEA1KZqAHiz
|
||||
1wCgb1IAr6+UAGXo/wDFk30AycSHAHfN+wDUqYsAqcrYAES95QCF2f4AhSwfADjK5gCOxOYAyrV+ALGa
|
||||
fAC7flkAosCzAGbH/wCRucAAFLf0AJNHPQDCztsAvIZtAF682ADawnUAsohkAKJcTwDH3/IA1KBQAMa7
|
||||
ogCZsKoAoWo+APfgrQC4u78A8tWaAMmSUQDLpJwAmEUhAI09MACSzN4A0Jk6AK5vWQCw1/IAy5huANW/
|
||||
lwDpwHMAzbBlABjL9ADbvKsAhsT0AKV6bgCod10Asod2ALavqQDqx4cA2K96AKRXLwDIjjwAwZGJAODE
|
||||
ngCbXDkAunpDAOW+ewDAhmAAcNT/ALJuMgCe0/8AhsS5AKOoogAluecAosrBAALY/QB/xf4AYsPNAMOo
|
||||
iwC3hVUAppmGADDD7QDgvJcADcD3AL6gdgCW2PQAiLfNAGzq/wC6s7QAorW3AKtlSgCaTkAAwoM3AKqD
|
||||
ZAC4d04A26xaAM+bWwDHqoIAbLa7AMuchQCsZDMA055IALzNhQC0gS8AV8XZAJ5RKQD45b8AZbn+AKVh
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAD////n//8AAP///8f//wAA///4A///
|
||||
AAD//8AB//8AAP//AAA//wAA//wAAB//AAD/8AAAB/8AAP/gAAAD/wAA/8AAAAD/AAD/gAAAAH8AAP8A
|
||||
AAAAfwAA/gAAAAA/AAD8AAAAAB8AAPwAAAAAHwAA+AAAAAAPAAD4AAAAAAcAAPAAAAAABwAA8AAAAAAH
|
||||
AADwAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAA
|
||||
AAAAAwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADwAAAAAAMAAPAAAAAABwAA8AAAAAAH
|
||||
AAD4AAAAAAcAAPgAAAAADwAA/AAAAAAfAAD8AAAAAB8AAP4AAAAAPwAA/wAAAAB/AAD/gAAAAP8AAP/A
|
||||
AAAB/wAA/+AAAAP/AAD/8AAAB/8AAP/8AAAH/wAA//8AAHf/AAD//+AB//8AAP///////wAA
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<generatePublisherEvidence enabled="false"/>
|
||||
</runtime>
|
||||
</configuration>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<generatePublisherEvidence enabled="false" />
|
||||
</runtime>
|
||||
</configuration>
|
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 772 B |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 339 B |