/* *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); }