static void Main(string[] args) { Logging.OpenLogFile(); myServer = new HTTPServer(); //check command line arguments int status; int howManyArgs = args.Length; string arg1; string arg2; string arg3; switch (howManyArgs) { case 0: arg1 = "empty"; arg2 = "empty"; arg3 = "empty"; break; case 1: arg1 = args[0]; arg2 = "empty"; arg3 = "empty"; break; case 2: arg1 = args[0]; arg2 = args[1]; arg3 = "empty"; break; case 3: arg1 = args[0]; arg2 = args[1]; arg3 = args[2]; break; default: arg1 = arg2 = arg3 = "Invalid"; break; } status = myServer.CheckArgs(arg1, arg2, arg3); if (status == myServer.IsVald) { //check web root directory if (!Directory.Exists(myServer.WebRoot)) { Console.WriteLine("The Path of Web Root Does not Exist!"); Logging.WriteLog("The Path of Web Root Does not Exist!"); return; } TcpListener server = null; //Init server bool isInit = myServer.InitServer(ref server); if (isInit) { //receive and respond myServer.ListenAndRespond(ref server); } } else if (status == myServer.IsHelp) { Console.WriteLine("Usage: myOwnWebServer -webRoot=[website root path] -webIP=[Server IP] -webPort=[Port Number]"); } else { Console.WriteLine("Invalid command line arguments format! Please use -h switch to check useage manual"); } }
/* *FUNCTION : InitServer *PARAMETERS : ref TcpListener server *RETURNS : bool : status that whether server is started or not *DESCRIPTION : This method starts the server with IP address and port that user input * This return false if exception happens, returns true if server is initiated without error */ public bool InitServer(ref TcpListener server) { bool status = true; try { Int32 Port = Int32.Parse(WebPort); IPAddress localAddr = IPAddress.Parse(WebIP); //create server server = new TcpListener(localAddr, Port); //start server server.Start(); //Console.WriteLine("Web Server Online!"); //Console.WriteLine("Server Root path: {0}", myServer.WebRoot); //Console.WriteLine("Server Port: {0}", myServer.WebPort); //Console.WriteLine("Server IP: {0}", myServer.WebIP); Logging.WriteLog($"Web Server Online! Root path: {WebRoot}, Port: {WebPort}, IP: {WebIP}"); } catch (SocketException e) { //Console.WriteLine("Socket Exception: {0}", e.Message); Logging.WriteLog($"Socket Exception: {e.Message}"); status = false; } catch (Exception e) { //Console.WriteLine("Exception: {0}", e.Message); Logging.WriteLog($"Exception: {e.Message}"); status = false; } return status; }
/* *FUNCTION : ListenAndRespond *PARAMETERS : ref TcpListener server: server that listen client *RETURNS : no return *DESCRIPTION : This method accept client and create a stream, through the stream it communicate with client * It enters infinite loop to get clients message in try block, if the stream has problem with connection * it throws exception. */ public void ListenAndRespond(ref TcpListener server) { // Buffer for reading data Byte[] bytes = new Byte[10240]; String request = null; try { // Enter the listening loop. while (true) { //Console.Write("Waiting for a connection... "); // Perform a blocking call to accept requests. // You could also user server.AcceptSocket() here. TcpClient client = server.AcceptTcpClient(); //Console.WriteLine("Connected!"); request = null; // Get a stream object for reading and writing NetworkStream stream = client.GetStream(); int i; // Loop to receive all the data sent by the client. while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { // Translate data bytes to a ASCII string. request = System.Text.Encoding.ASCII.GetString(bytes, 0, i); //Console.WriteLine("Received: {0}", request); // parse the request and return the full response byte[] respondMsg = ParseRequest(request); //log request header Logging.WriteLog(HTTPRequestHeader); // string respondMsg = request.ToUpper(); //serialize the response //byte[] msg = System.Text.Encoding.Default.GetBytes(respondMsg); // Send back a response. stream.Write(respondMsg, 0, respondMsg.Length); //Console.WriteLine("Response Sent..."); //log response header Logging.WriteLog(HTTPResponseHeader); //clear the messages HTTPRequestHeader = ""; HTTPResponseBody = ""; HTTPResponseHeader = ""; } // Shutdown and end connection client.Close(); } } catch (SocketException e) { //Console.WriteLine("SocketException: {0}", e.Message); Logging.WriteLog($"SocketException: {e.Message}"); } catch (Exception e) { Logging.WriteLog($"Exception: {e.Message}"); } }
/* *FUNCTION : ParseRequest *PARAMETERS : string request : The request string from the client *RETURNS : byte[] : A byte array that contains response *DESCRIPTION : This method first,parse header of the request. second, find the file that client request, * third, generate header and body of response, forth, combine header and body in byte array form * It fill the header with error code and error message if errors accur */ public byte[] ParseRequest(string request) { try { string requestFirstLine = request.Substring(0, request.IndexOf('\r')); string requestTheRest = request.Substring(request.IndexOf('\n') + 1); //In the parsed first line the [0] is method, the [1] is file path, the [2] is HTML Version string[] parsedRequestFirstLine = requestFirstLine.Split(' '); string method = parsedRequestFirstLine[0]; string filePath = WebRoot + parsedRequestFirstLine[1]; string requestSecondLine = requestTheRest.Substring(0, requestTheRest.IndexOf('\r')); //creat the request header HTTPRequestHeader = requestFirstLine + Environment.NewLine + requestSecondLine; //method is not GET if (method != "GET") { StatusCode = "405 Method Not Allowed"; } //file does not exist else if(!File.Exists(filePath)) { StatusCode = "404 Not Found"; } else { //check suffix if not found in dictionary 406 FileSuffix = Path.GetExtension(filePath); if(!MIMETypes.ContainsKey(FileSuffix)) { StatusCode = "406 Not Acceptable"; } else { byte[] content = File.ReadAllBytes(filePath); byteBody = content; ContentLength = content.Length; // all OK 200 StatusCode = "200 OK"; } } //after parsing build the response BuildResponse(); } catch (Exception e) { // File I/O exceptions 500 if( e is ArgumentException || e is ArgumentNullException || e is PathTooLongException || e is IOException || e is UnauthorizedAccessException) { StatusCode = "500 Internal Server Error"; } //parse exception 400 else { StatusCode = "400 Bad Request"; } //Console.WriteLine($"Exception:{e.Message}"); Logging.WriteLog($"Exception:{e.Message}"); BuildResponse(); } if(StatusCode!="200 OK") { byteBody = System.Text.Encoding.UTF8.GetBytes(HTTPResponseBody); } byte[] byteHeader = System.Text.Encoding.UTF8.GetBytes(HTTPResponseHeader + Environment.NewLine + Environment.NewLine); return Combine(byteHeader, byteBody); }