//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // Information Contained Herein is Proprietary and Confidential. // //------------------------------------------------------------------------------ using System; using System.Diagnostics; using Microsoft.VisualStudio.WebHost; using System.Globalization; using Microsoft.Singularity; using Microsoft.Singularity.Io; using Microsoft.Singularity.Configuration; using Microsoft.Singularity.Channels; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; [assembly: Transform(typeof(ApplicationResourceTransform))] namespace Microsoft.VisualStudio.WebServer { [ConsoleCategory(HelpMessage="cassini [options] A web server", DefaultAction=true)] internal sealed class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [BoolParameter( "v", Default=false , HelpMessage="Verbose")] internal bool verbose; [BoolParameter( "s", Default=false , HelpMessage="Silent")] internal bool silent; [BoolParameter( "quitURL", Default=false , HelpMessage="Allow special URL to terminate")] internal bool quitURL; [StringParameter( "port", Default=null , HelpMessage="Port ID to listen to")] internal string portString; [StringParameter( "vpath", Default="", HelpMessage="Root of Virtual Path")] internal string virtualPath; [StringParameter( "client", Default="", HelpMessage="Client IP")] internal string client; [StringParameter( "apparg", Default="", HelpMessage="Arg to pass to client app")] internal string appArg; [StringParameter( "app", Mandatory=true, Default="", HelpMessage="Name of the app to run")] internal string app; reflective internal Parameters(); internal int AppMain() { return WebServerApp.AppMain(this); } } public sealed class WebServerApp { internal static int AppMain(Parameters! config) { bool verbose = config.verbose; bool silent = config.silent; string virtualPath = config.virtualPath; if (virtualPath != null) { virtualPath = virtualPath.Trim(); } if ((virtualPath == null) || (virtualPath.Length == 0)) { virtualPath = "/"; } else { if (virtualPath.StartsWith("/") == false) { if (!silent) { ShowUsage(); } return -1; } } string physicalPath = "\\"; /* HACKHACK FIXME: the file system is not wired up in Singularity; avoid using it! string physicalPath = (string)commandLine.Options["path"]; if (physicalPath != null) { physicalPath = physicalPath.Trim(); } if ((physicalPath == null) || (physicalPath.Length == 0)) { if (!silent) { ShowUsage(); } return -1; } else { if (Directory.Exists(physicalPath) == false) { if (!silent) { ShowMessage("The physical path '"+ physicalPath + "' does not exist!"); } return -2; } // added this to resolve paths like "." physicalPath = Path.GetFullPath(physicalPath); } */ int port = 0; string portText = config.portString; if (portText != null) { portText = portText.Trim(); } if ((portText != null) && (portText.Length != 0)) { try { port = Int32.Parse(portText); if ((port < 1) || (port > 65535)) { if (!silent) { ShowUsage(); } return -1; } } catch { if (!silent) { ShowMessage("Invalid port '" + portText + "'"); } return -3; } } else { port = 80; } // clientIP was added so that we could test using Cassini remotely on // lab machines. This now allows the client to be localhost or clientIP. string clientIP = config.client; if (clientIP != null) { clientIP = clientIP.Trim(); } if ((clientIP == null) || (clientIP.Length == 0)) { clientIP = "localhost"; } // // Singularity-specific initialization // string webApp = config.app; bool quitURL = config.quitURL; // FIXME: should generalize this so more than one arg can be passed to // the webapp! string[] appArgs = null; if (config.appArg != null) { appArgs = new string[1]; appArgs[0] = config.appArg; } if ((webApp == null) || (webApp.Length == 0)) { webApp = "HelloWebApp.x86"; } webApp.Trim(); if (!Dispatcher.Initialize(webApp, appArgs, verbose, quitURL)) { if (!silent) { ShowMessage("Invalid web application name \"" + webApp + "\""); return -5; } } // ==================== // Actually start the server below // =================== try { Server server = new Server(port, virtualPath, physicalPath, clientIP); server.Start(); String s1 = String.Format( Environment.NewLine + "Running Web Server on port {0}." + Environment.NewLine + Environment.NewLine + "Application '{1}' is mapped to '{2}'." + Environment.NewLine + Environment.NewLine, port, virtualPath, physicalPath); String s2 = String.Format( "http://localhost:{0}{1}", port, virtualPath); if (!s2.EndsWith("/")) s2 += "/"; Console.WriteLine(s1+s2+Environment.NewLine); // Currently no console-read support in Singularity. Run forever! //Console.WriteLine("Hit Enter to stop the server"); //Console.ReadLine(); //server.Stop(); } catch (Exception ex) { if (!silent) { ShowMessage("Error opening port " + port + ": " + ex.Message); } return -5; } return 0; } private static void ShowUsage() { string usageString; usageString = "Invalid usage.\n\n"; usageString += "cassini [options]\n"; usageString += "Options:\n"; usageString += " -app: run application.\n"; usageString += " -apparg: supply argument to application.\n"; usageString += " -path:\n"; usageString += " -port:\n"; usageString += " -quitURL quit if URL ending in \"quit\" is received.\n"; usageString += " [-silent]\n"; usageString += " [-verbose] show files served\n"; usageString += " [-vpath:]\n"; usageString += " [-client:]\n"; ShowMessage(usageString); } private static void ShowMessage(String msg) { Console.WriteLine("Visual Web Developer Web Server:\n" + msg); } } }