-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #221 from aura-systems/impl-httpserver
Basic HTTP Server Implementation.
- Loading branch information
Showing
11 changed files
with
1,345 additions
and
0 deletions.
There are no files selected for viewing
40 changes: 40 additions & 0 deletions
40
Aura Operating System/Aura_OS/System/Network/SimpleHttpServer/HttpBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* PROJECT: Aura Operating System Development | ||
* CONTENT: Http default responses | ||
* PROGRAMMERS: Valentin Charbonnier <[email protected]> | ||
* David Jeske | ||
* Barend Erasmus | ||
* LICENSE: LICENSES\SimpleHttpServer\LICENSE.md | ||
*/ | ||
|
||
using SimpleHttpServer.Models; | ||
|
||
namespace SimpleHttpServer | ||
{ | ||
class HttpBuilder | ||
{ | ||
public static HttpResponse InternalServerError() | ||
{ | ||
string content = "<h1>500 Internal Server Error</h1><a href=\"http://141.94.79.247\">Back to home page</a>"; | ||
|
||
return new HttpResponse() | ||
{ | ||
ReasonPhrase = "InternalServerError", | ||
StatusCode = "500", | ||
ContentAsUTF8 = content | ||
}; | ||
} | ||
|
||
public static HttpResponse NotFound() | ||
{ | ||
string content = "<h1>404 Not Found</h1><a href=\"http://141.94.79.247\">Back to home page</a>"; | ||
|
||
return new HttpResponse() | ||
{ | ||
ReasonPhrase = "NotFound", | ||
StatusCode = "404", | ||
ContentAsUTF8 = content | ||
}; | ||
} | ||
} | ||
} |
231 changes: 231 additions & 0 deletions
231
Aura Operating System/Aura_OS/System/Network/SimpleHttpServer/HttpProcessor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
/* | ||
* PROJECT: Aura Operating System Development | ||
* CONTENT: HttpProcessor class | ||
* PROGRAMMERS: Valentin Charbonnier <[email protected]> | ||
* David Jeske | ||
* Barend Erasmus | ||
* LICENSE: LICENSES\SimpleHttpServer\LICENSE.md | ||
*/ | ||
|
||
using Cosmos.System.Network.IPv4; | ||
using Cosmos.System.Network.IPv4.TCP; | ||
using SimpleHttpServer.Models; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace SimpleHttpServer | ||
{ | ||
//used because Event with return type is not supported by Cosmos. | ||
public class HttpDiscussion | ||
{ | ||
public HttpRequest Request; | ||
public HttpResponse Response; | ||
} | ||
|
||
public class HttpProcessor | ||
{ | ||
private List<Route> Routes = new List<Route>(); | ||
|
||
public HttpProcessor() | ||
{ | ||
|
||
} | ||
|
||
public void HandleClient(TcpClient tcpClient) | ||
{ | ||
//get request from client | ||
var request = GetRequest(tcpClient); | ||
|
||
// route and handle the request... | ||
var response = RouteRequest(tcpClient, request); | ||
|
||
Console.WriteLine("{0} {1}", response.StatusCode, request.Url); | ||
|
||
// build a default response for errors | ||
if (response.Content == null) | ||
{ | ||
if (response.StatusCode != "200") | ||
{ | ||
response.ContentAsUTF8 = string.Format("{0} {1} <p> {2}", response.StatusCode, request.Url, response.ReasonPhrase); | ||
} | ||
} | ||
|
||
WriteResponse(tcpClient, response); | ||
|
||
tcpClient.Close(); | ||
} | ||
|
||
private HttpRequest GetRequest(TcpClient client) | ||
{ | ||
var ep = new EndPoint(Address.Zero, 0); | ||
|
||
//Read Request Line | ||
string request = Encoding.ASCII.GetString(client.Receive(ref ep)); | ||
|
||
var lines = request.Split("\r\n"); | ||
|
||
string[] tokens = lines[0].Split(' '); | ||
|
||
if (tokens.Length != 3) | ||
{ | ||
throw new Exception("invalid http request line"); | ||
} | ||
|
||
string method = tokens[0].ToUpper(); | ||
string url = tokens[1]; | ||
string protocolVersion = tokens[2]; | ||
|
||
//Read Headers | ||
Dictionary<string, string> headers = new Dictionary<string, string>(); | ||
|
||
for (int i = 1; i < lines.Length; i++) | ||
{ | ||
if (lines[i].Equals("")) | ||
{ | ||
break; | ||
} | ||
|
||
int separator = lines[i].IndexOf(':'); | ||
if (separator == -1) | ||
{ | ||
throw new Exception("invalid http header line: " + lines[i]); | ||
} | ||
string name = lines[i].Substring(0, separator); | ||
int pos = separator + 1; | ||
while ((pos < lines[i].Length) && (lines[i][pos] == ' ')) | ||
{ | ||
pos++; | ||
} | ||
|
||
string value = lines[i].Substring(pos, lines[i].Length - pos); | ||
headers.Add(name, value); | ||
} | ||
|
||
/* | ||
string content = null; | ||
if (headers.ContainsKey("Content-Length")) | ||
{ | ||
int totalBytes = Convert.ToInt32(headers["Content-Length"]); | ||
int bytesLeft = totalBytes; | ||
byte[] bytes = new byte[totalBytes]; | ||
while(bytesLeft > 0) | ||
{ | ||
byte[] buffer = new byte[bytesLeft > 1024? 1024 : bytesLeft]; | ||
int n = inputStream.Read(buffer, 0, buffer.Length); | ||
buffer.CopyTo(bytes, totalBytes - bytesLeft); | ||
bytesLeft -= n; | ||
} | ||
content = Encoding.ASCII.GetString(bytes); | ||
}*/ | ||
|
||
return new HttpRequest() | ||
{ | ||
Method = method, | ||
Url = url, | ||
Headers = headers, | ||
Content = "content" //TODO: add content | ||
}; | ||
} | ||
|
||
protected virtual HttpResponse RouteRequest(TcpClient client, HttpRequest request) | ||
{ | ||
if (!Routes.Any()) | ||
{ | ||
return HttpBuilder.NotFound(); | ||
} | ||
|
||
//Search Route | ||
var route = GetRoute(request); | ||
|
||
if (route == null) | ||
{ | ||
return HttpBuilder.NotFound(); | ||
} | ||
|
||
// trigger the route handler... | ||
try | ||
{ | ||
var discussion = new HttpDiscussion() { Request = request, Response = null }; | ||
|
||
route.Callable(discussion); | ||
|
||
return discussion.Response; | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine(ex); | ||
|
||
return HttpBuilder.InternalServerError(); | ||
} | ||
} | ||
|
||
private Route GetRoute(HttpRequest request) | ||
{ | ||
foreach (var route in Routes) | ||
{ | ||
if (route.Url == request.Url) | ||
{ | ||
return route; | ||
} | ||
} | ||
|
||
//no hardcoded route, get filesystem root | ||
|
||
if (request.Url == "/") | ||
{ | ||
request.Url = "/index.html"; | ||
} | ||
|
||
foreach (var route in Routes) | ||
{ | ||
if (route.Url == "") | ||
{ | ||
return route; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
// this formats the HTTP response... | ||
private static void WriteResponse(TcpClient client, HttpResponse response) | ||
{ | ||
if (response.Content == null) | ||
{ | ||
response.Content = new byte[] { }; | ||
} | ||
|
||
// default to text/html content type | ||
if (!response.Headers.ContainsKey("Content-Type")) | ||
{ | ||
response.Headers["Content-Type"] = "text/html"; | ||
} | ||
|
||
response.Headers["Content-Length"] = response.Content.Length.ToString(); | ||
|
||
//make response | ||
var sb = new StringBuilder(); | ||
sb.Append(string.Format("HTTP/1.0 {0} {1}\r\n", response.StatusCode, response.ReasonPhrase)); | ||
foreach (var header in response.Headers) | ||
{ | ||
sb.Append(header.Key + ": " + header.Value + "\r\n"); | ||
} | ||
sb.Append("\r\n"); | ||
sb.Append(Encoding.ASCII.GetString(response.Content)); | ||
|
||
client.Send(Encoding.ASCII.GetBytes(sb.ToString())); | ||
} | ||
|
||
public void AddRoute(Route route) | ||
{ | ||
Routes.Add(route); | ||
} | ||
|
||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
Aura Operating System/Aura_OS/System/Network/SimpleHttpServer/HttpServer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* PROJECT: Aura Operating System Development | ||
* CONTENT: HttpServer class | ||
* PROGRAMMERS: Valentin Charbonnier <[email protected]> | ||
* David Jeske | ||
* Barend Erasmus | ||
* LICENSE: LICENSES\SimpleHttpServer\LICENSE.md | ||
*/ | ||
|
||
using Cosmos.System.Network.IPv4.TCP; | ||
using SimpleHttpServer.Models; | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace SimpleHttpServer | ||
{ | ||
public class HttpServer | ||
{ | ||
#region Fields | ||
|
||
private int Port; | ||
private TcpListener Listener; | ||
private HttpProcessor Processor; | ||
private bool IsActive = true; | ||
|
||
#endregion | ||
|
||
#region Public Methods | ||
|
||
public HttpServer(int port, List<Route> routes) | ||
{ | ||
Port = port; | ||
Processor = new HttpProcessor(); | ||
|
||
foreach (var route in routes) | ||
{ | ||
Processor.AddRoute(route); | ||
} | ||
} | ||
|
||
public void Listen() | ||
{ | ||
Listener = new TcpListener((ushort)Port); | ||
Listener.Start(); | ||
|
||
Console.WriteLine("HTTP Server Listening on port 80..."); | ||
|
||
while (IsActive) | ||
{ | ||
try | ||
{ | ||
var s = Listener.AcceptTcpClient(); | ||
Processor.HandleClient(s); | ||
} | ||
catch | ||
{ | ||
|
||
} | ||
} | ||
} | ||
|
||
#endregion | ||
|
||
} | ||
} | ||
|
||
|
||
|
52 changes: 52 additions & 0 deletions
52
Aura Operating System/Aura_OS/System/Network/SimpleHttpServer/Models/HttpRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* PROJECT: Aura Operating System Development | ||
* CONTENT: HttpRequest class | ||
* PROGRAMMERS: Valentin Charbonnier <[email protected]> | ||
* David Jeske | ||
* Barend Erasmus | ||
* LICENSE: LICENSES\SimpleHttpServer\LICENSE.md | ||
*/ | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace SimpleHttpServer.Models | ||
{ | ||
public class HttpRequest | ||
{ | ||
public string Method { get; set; } | ||
public string Url { get; set; } | ||
public string Content { get; set; } | ||
public Dictionary<string, string> Headers { get; set; } | ||
|
||
public HttpRequest() | ||
{ | ||
this.Headers = new Dictionary<string, string>(); | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
if (!string.IsNullOrWhiteSpace(this.Content)) | ||
{ | ||
if (!Headers.ContainsKey("Content-Length")) | ||
{ | ||
Headers.Add("Content-Length", Content.Length.ToString()); | ||
} | ||
|
||
} | ||
|
||
//make string from fields | ||
var sb = new StringBuilder(); | ||
sb.Append(Method + " " + Url + " HTTP/1.0\r\n"); | ||
foreach (var header in Headers) | ||
{ | ||
sb.Append(header.Key + ": " + header.Value + "\r\n"); | ||
} | ||
sb.Append("\r\n"); | ||
sb.Append(Content); | ||
|
||
return sb.ToString(); | ||
} | ||
} | ||
} |
Oops, something went wrong.