//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // Information Contained Herein is Proprietary and Confidential. // //------------------------------------------------------------------------------ namespace Microsoft.Singularity.WebServer { #if GCPROFILE using Microsoft.Singularity.Diagnostics; #endif using System; using System.Web; using System.Diagnostics; using System.Globalization; // Establish a port and listen on it. This is the base of the Server. public sealed class HttpServer { public static int Main(string[]! args) { #if GCPROFILE // Before we do anything else, start profiling. Eventually, the profiler // should be injected by the OS at process launch, based on config. If // this means compiling a different version of the binary for that purpose, // it should cache the extra binary. CLRProfiler.StartProfiling(); #endif CommandLine commandLine = new CommandLine(args); bool silent = (commandLine.Options["silent"] != null); if (!silent && commandLine.ShowHelp) { ShowUsage(); return 0; } // The server is started with mapping information from requests // to applications. Initially, we will ignore the map and // do a default map based on the UriPath. But eventually this // is where the configuration and appmodel will be introduced. // TODO: establish non-default mappings from requests to apps. string mapping = (string)commandLine.Options["mapping"]; if (mapping != null) { mapping = mapping.Trim(); } if ((mapping == null) || (mapping.Length == 0)) { mapping = "/"; } else { // TODO: validate that mapping points somewhere useful. } int port = 0; string portText = (string)commandLine.Options["port"]; 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 = (string)commandLine.Options["client"]; if (clientIP != null) { clientIP = clientIP.Trim(); } if ((clientIP == null) || (clientIP.Length == 0)) { clientIP = "localhost"; } // ==================== // Start listening // =================== try { Listener listener = new Listener(port, clientIP); listener.Start(); String s1 = String.Format(Environment.NewLine + "Running Web Server on port {0}." + Environment.NewLine, port); Console.WriteLine(s1); } catch (Exception ex) { if (!silent) { ShowMessage("Error opening port " + port + ": " + ex.Message); } return -5; } return 0; // TODO: There is no support for stopping the server, beyond process // death. Do we need a more orderly notion, or should all the different // processes observe disconnected channels and do their own thing? // // Add support for this server to stop listening and terminate its // process; assume that no additional protocol is required. } private static void ShowUsage() { string usageString; usageString = "Invalid usage.\n\n"; usageString += "WebServer [options]\n"; usageString += "Options:\n"; usageString += " [-port:]\n"; usageString += " [-silent]\n"; usageString += " [-mapping:]\n"; usageString += " [-client:]\n"; ShowMessage(usageString); } private static void ShowMessage(String msg) { Console.WriteLine("Singularity Web Server:\n" + msg); } } }