/* * Webserver for ETA031 * Developer: Filip Ekberg * Date: 2007-02 * */ #region Usings using System; using System.Net; using System.Net.Sockets; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.ComponentModel; using System.IO; #endregion namespace WebServer { public class FRW_HTTPD { #region Class Members private const int PORT = 80; // Listen to this port private const string WWWROOT = "./www/"; // The wwwroot private string[] Indexes = { "index.html", "index.htm", "default.htm", "default.html" }; private string[] MIMES = { "text/html", "image/gif", "image/jpeg" }; private Socket Server, Client; // The Sockets #endregion #region Constructors public FRW_HTTPD() { Logger.Log("Starting Service"); // Init the webserver init(); } #endregion #region Thread Handle void handleConnection() { Logger.Log("-- Processing Client --"); try { Socket client = this.Client; IPEndPoint clientIEP = client.RemoteEndPoint as IPEndPoint; Logger.Log(String.Format("Connected with {0} at port {1}", clientIEP.Address, clientIEP.Port)); Logger.Log(Receive(client)); } catch (SocketException ex) { throw ex; } } #endregion #region Initialize Web Server /// /// Initializes the Webserver, starts the sockets and listens to incomming Clients /// protected void init() { // Retreive an IPHostEntry based on 127.0.0.1 IPHostEntry localhost = Dns.GetHostByName(Dns.GetHostName()); // Set the IP End Point to the localhost and port to the constant PORT IPEndPoint eip = new IPEndPoint(localhost.AddressList[0], PORT); // Create a socket using TCP Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Bind the server to the IP End Point Server.Bind(eip); // Start listening Server.Listen(10); // As long as the program is running, listen for new clients while (true) { Logger.Log("-- Wating for client --"); // As soon as a client connects, start a new thread and begin process Client = Server.Accept(); ThreadStart job = new ThreadStart(handleConnection); Thread thread = new Thread(job); thread.Start(); } } #endregion #region Data Handle #region Send /// /// Transmits data to a Socket. /// /// The Receiving Socket /// The Data that we want to transmit private void Send(Socket receiver, string Data) { byte[] data = new byte[Data.Length]; data = Encoding.ASCII.GetBytes(Data); int total = 0, size = data.Length, dataLeft = size, sent; // While we still have bytes to transmit // send data to the receiver. while (total < size) { sent = receiver.Send(data, total, dataLeft, SocketFlags.None); total += sent; dataLeft -= sent; } } private void Send(Socket receiver, string Data, byte[] stream) { byte[] data = new byte[Data.Length + stream.Length + 10]; byte[] data_2 = Encoding.ASCII.GetBytes(Data); data_2.CopyTo(data, 0); stream.CopyTo(data, 0); int total = 0, size = data.Length, dataLeft = size, sent; // While we still have bytes to transmit // send data to the receiver. while (total < size) { sent = receiver.Send(data, total, dataLeft, SocketFlags.None); total += sent; dataLeft -= sent; } } #endregion #region SendHTML private void SendHTML(Socket receiver, string HTML, string Content_Type, int Content_Lengt, string status_code) { string Data = ""; Data +="\n\nHTTP/1.1 " + status_code; Data += "\nContent-Type: " + Content_Type; Data += "\nServer: frrWD"; Data += "\nContent-Length: " + Content_Lengt; Data += "\nDate: Tue, 20 Feb 2007 22:10:54 GMT\n"; Data += "\n" + HTML; Send(receiver, Data); } #endregion #region SendOther private void SendOther(Socket receiver, byte[] stream, string Content_Type, int Content_Lengt, string status_code) { string Data = ""; Data += "\n\nHTTP/1.1 " + status_code; Data += "\nContent-Type: " + Content_Type; Data += "\nContent-Transfer-Encoding: binary"; Data += "\nServer: frrWD"; Data += "\nContent-Length: " + Content_Lengt; Data += "\nDate: Tue, 20 Feb 2007 22:10:54 GMT\n"; Send(receiver, Data, stream); } #endregion #region SendError private void SendError(Socket sender, string error, string Code) { string html = "An Error has Occured:
" + error + "
"; SendHTML(sender, html, "text/html", html.Length, Code); } #endregion #region Receive private string Receive(Socket sender) { byte[] data = new byte[0]; while (sender.Connected) { if (sender.Available > 0) { data = new byte[sender.Available]; sender.Receive(data); } else if (Regex.IsMatch(Encoding.ASCII.GetString(data), "(.*)\\r\\n\\r\\n", RegexOptions.Multiline)) { Logger.Log("Exit"); string raw = Encoding.ASCII.GetString(data); int IndexOf = raw.IndexOf("\r\n"); raw = raw.Substring(0, IndexOf); ParseRequest(sender, raw); sender.Close(); break; } } return Encoding.ASCII.GetString(data) ; } #endregion #region Request #region Parse Method private void ParseRequest(Socket sender, string raw) { string[] Methods = raw.Split(' '); switch (Methods[0]) { case "HEAD": case "POST": SendError(sender, "Not Yet Implemented", "501 Not Implemented"); break; case "GET": if (Methods[1].Equals("/")) { bool indexFound = FindeIndex(sender); if (!indexFound) { SendError(sender, "

Directory Listing DENIED!

", "200 OK"); } } else { DirectoryInfo dr = new DirectoryInfo("."); Logger.Log(dr.FullName); if (FindFile(Methods[1])) RequestFile(sender, Methods[1]); else SendError(sender, "

404 Not Found

", "404 Not Found"); } break; } } #endregion #region FindIndex private bool FindeIndex(Socket sender) { foreach (string index in Indexes) { if (FindFile(index)) { RequestFile(sender, index); return true; } } return false; } #endregion #region Find File private bool FindFile(string FileName) { FileInfo file = new FileInfo(WWWROOT + FileName); return file.Exists; } #endregion #region Request File public void RequestFile(Socket sender, string Filename) { FileInfo theFile = new FileInfo(WWWROOT + Filename); FileStream requestedFile = File.Open(WWWROOT + Filename, FileMode.Open); byte[] data = new byte[requestedFile.Length]; requestedFile.Read(data, 0, (int)requestedFile.Length); if (requestedFile.CanRead) { string mime; string extension = theFile.Extension; extension = extension.Trim('.'); extension = extension.ToLower(new System.Globalization.CultureInfo("sv-SE", false)); switch (extension) { case "jpg": mime = MIMES[2]; SendOther(sender, data, mime, (int)requestedFile.Length, "200 OK"); break; case "gif": mime = MIMES[1]; SendOther(sender, data, mime, (int)requestedFile.Length, "200 OK"); break; default: mime = MIMES[0]; SendHTML(sender, Encoding.ASCII.GetString(data), mime, (int)requestedFile.Length, "200 OK"); break; } } else { SendError(sender, "

403 Access Denied

", "403 Not Found"); } requestedFile.Close(); } #endregion #endregion #endregion } }