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