Dodaj pliki projektów.
This commit is contained in:
parent
2871ac9ef5
commit
ec256f2f53
343
Program.cs
Normal file
343
Program.cs
Normal file
@ -0,0 +1,343 @@
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace myownhttp
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
public enum HTTPMeth
|
||||
{
|
||||
undefined = -1,
|
||||
GET = 0,
|
||||
POST = 1 // add more in future
|
||||
}
|
||||
public class HTTPReq
|
||||
{
|
||||
public bool valid = false;
|
||||
|
||||
public string Path = "";
|
||||
public string HTTPVersion = "";
|
||||
public string Content = "";
|
||||
public HTTPMeth Method = HTTPMeth.undefined;
|
||||
|
||||
|
||||
public Dictionary<string,string> Headers = new Dictionary<string,string>();
|
||||
|
||||
public HTTPReq(string request)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var split = request.ReplaceLineEndings().Split(Environment.NewLine);
|
||||
var splitfirst = split[0].Split(" ");
|
||||
if (splitfirst[0] == "GET") Method = HTTPMeth.GET;
|
||||
else if (splitfirst[0] == "POST") Method = HTTPMeth.POST;
|
||||
Path = splitfirst[1]; // check if the path
|
||||
HTTPVersion = splitfirst[2];
|
||||
|
||||
// headers
|
||||
for (int i = 1; i < split.Length; i++)
|
||||
{
|
||||
var e = split[i];
|
||||
if(e == "")
|
||||
{
|
||||
if(i+1 < split.Length)
|
||||
{
|
||||
var arraycontent = split.Skip(i);
|
||||
foreach(var item in arraycontent)
|
||||
{
|
||||
Content += item + "\r\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
var esplit = e.Split(": ");
|
||||
Headers.Add(esplit[0], esplit[1]);
|
||||
|
||||
}
|
||||
|
||||
valid = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"HTTP REQUEST -> {(valid ? "Valid" : "Invalid")}, {(Method switch { HTTPMeth.undefined => "Unset/Undefined", HTTPMeth.GET => "GET", HTTPMeth.POST => "POST", _ => "MError"})} {Path} {HTTPVersion}";
|
||||
}
|
||||
|
||||
}
|
||||
public class HTTPRes
|
||||
{
|
||||
byte[] contentBytes = [];
|
||||
public byte[] GetBytes() { return contentBytes; }
|
||||
public HTTPRes SetBytes(byte[] bytes) { contentBytes = bytes; return this; }
|
||||
public HTTPRes SetBytes(string str) { contentBytes = Encoding.UTF8.GetBytes(str); return this; }
|
||||
|
||||
public string ContentType = GetMimeType("txt");
|
||||
string Status = GetStatusFromNum(200);
|
||||
|
||||
public string GetStatus() { return Status; }
|
||||
public HTTPRes SetStatus(int num) { SetStatus(GetStatusFromNum(num)); return this; }
|
||||
public HTTPRes SetStatus(string status) { Status = status; return this; }
|
||||
|
||||
|
||||
public byte[] Build()
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(
|
||||
$"HTTP/1.1 {Status}\r\n" +
|
||||
$"Content-Type: {ContentType}{(ContentType.Contains("text") ? "; charset=utf-8" : "")}\n" +
|
||||
$"Content-Length: {contentBytes.Length}" +
|
||||
$"\n" +
|
||||
$"\n"
|
||||
).Concat(contentBytes).ToArray();
|
||||
}
|
||||
}
|
||||
public abstract class HTTPHandler
|
||||
{
|
||||
public HTTPHandler() { }
|
||||
|
||||
public virtual void Handle(HTTPReq request, HTTPRes response, Action next)
|
||||
{
|
||||
// this is just a base, do nothing
|
||||
next();
|
||||
}
|
||||
}
|
||||
public class HTTPGetHandler : HTTPHandler
|
||||
{
|
||||
string Path = "";
|
||||
Action<HTTPReq, HTTPRes, Action> Action = (HTTPReq req, HTTPRes res, Action next) => { };
|
||||
public HTTPGetHandler(string path, Action<HTTPReq, HTTPRes, Action> action) { Path = path; Action = action; }
|
||||
|
||||
public override void Handle(HTTPReq request, HTTPRes response, Action next)
|
||||
{
|
||||
if (request.Path == Path) Action(request, response, next);
|
||||
else next();
|
||||
}
|
||||
}
|
||||
public class HTTPServeFileHandler : HTTPHandler
|
||||
{
|
||||
HTTPGetHandler replacement;
|
||||
public HTTPServeFileHandler(string path, string filepath, string MimeType)
|
||||
{
|
||||
replacement = new(path, (req, res, next) =>
|
||||
{
|
||||
if (File.Exists(filepath))
|
||||
{
|
||||
res.SetBytes(File.ReadAllBytes(filepath)).SetStatus(200).ContentType = MimeType;
|
||||
}
|
||||
else next();
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public override void Handle(HTTPReq request, HTTPRes response, Action next)
|
||||
{
|
||||
replacement.Handle(request, response, next);
|
||||
}
|
||||
}
|
||||
|
||||
public class HTTPStaticFilesHandler : HTTPHandler
|
||||
{
|
||||
string Files = "";
|
||||
public HTTPStaticFilesHandler(string pathWithStatic) { Files = pathWithStatic; }
|
||||
|
||||
public override void Handle(HTTPReq request, HTTPRes response, Action next)
|
||||
{
|
||||
var pat = request.Path.Replace("..", "");
|
||||
if (pat.EndsWith("/")) pat += "index.html";
|
||||
if (File.Exists(Files + Path.DirectorySeparatorChar + pat))
|
||||
{
|
||||
var ex = Path.GetExtension(Files + Path.DirectorySeparatorChar + pat);
|
||||
if (ex == string.Empty) ex = ".txt";
|
||||
ex = ex.Substring(1);
|
||||
response.SetBytes(File.ReadAllBytes(Files + Path.DirectorySeparatorChar + pat)).SetStatus(200).ContentType = GetMimeType(ex);
|
||||
}
|
||||
else next();
|
||||
}
|
||||
}
|
||||
public class HTTPConditionHandler : HTTPHandler
|
||||
{
|
||||
HTTPHandler Handler = null;
|
||||
Func<HTTPReq, HTTPRes, bool> Condition = (HTTPReq request, HTTPRes response) => { return false; };
|
||||
public HTTPConditionHandler(Func<bool> cond, HTTPHandler handler) { Handler = handler; }
|
||||
|
||||
public override void Handle(HTTPReq request, HTTPRes response, Action next)
|
||||
{
|
||||
if(Handler == null || !Condition(request,response))
|
||||
{
|
||||
next();
|
||||
return;
|
||||
}
|
||||
Handler.Handle(request, response, next);
|
||||
}
|
||||
}
|
||||
public class HTTPServer
|
||||
{
|
||||
TcpListener listener;
|
||||
public HTTPServer(int port)
|
||||
{
|
||||
listener = new(IPAddress.Any, 8003);
|
||||
|
||||
}
|
||||
|
||||
public List<HTTPHandler> Handlers = new();
|
||||
|
||||
public void Listen()
|
||||
{
|
||||
listener.Start();
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = listener.AcceptTcpClient();
|
||||
|
||||
var s = a.GetStream();
|
||||
|
||||
byte[] bytes = new byte[2048];
|
||||
string data = null;
|
||||
|
||||
int i;
|
||||
// Loop to receive all the data sent by the client.
|
||||
while ((i = s.Read(bytes, 0, bytes.Length)) != 0)
|
||||
{
|
||||
// Translate data bytes to a ASCII string.
|
||||
data = Encoding.ASCII.GetString(bytes, 0, i);
|
||||
|
||||
var req = new HTTPReq(data);
|
||||
|
||||
Console.WriteLine(req.ToString());
|
||||
|
||||
if (req.valid)
|
||||
{
|
||||
HTTPRes res = new HTTPRes();
|
||||
int nextAct = 0;
|
||||
Action next = () => { };
|
||||
next = () => {
|
||||
if(nextAct >= Handlers.Count)
|
||||
{
|
||||
|
||||
res.SetBytes("404 Not found.").SetStatus(404).ContentType = GetMimeType("txt");
|
||||
|
||||
} else
|
||||
{
|
||||
Handlers[nextAct].Handle(req, res, () => {
|
||||
|
||||
nextAct++;
|
||||
next();
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
next();
|
||||
|
||||
s.Write(res.Build());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Send back a response.
|
||||
var nf = "uuh";
|
||||
var nfb = Encoding.UTF8.GetBytes(nf);
|
||||
s.Write(
|
||||
Encoding.UTF8.GetBytes(
|
||||
$"HTTP/1.1 404 Not Found\n" +
|
||||
$"Content-Type: text/plain; charset=utf-8\n" +
|
||||
$"Content-Length: {nfb.Length}" +
|
||||
$"\n" +
|
||||
$"\n" +
|
||||
$"{nf}"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("hello");
|
||||
|
||||
HTTPServer http = new(8003);
|
||||
|
||||
http.Handlers.Add(new HTTPStaticFilesHandler("htdocs"));
|
||||
|
||||
/*http.Handlers.Add(new HTTPGetHandler("/", (req, res, next) =>
|
||||
{
|
||||
res.SetStatus(200).SetBytes("Hello! This is a test");
|
||||
}));
|
||||
http.Handlers.Add(new HTTPGetHandler("/2", (req, res, next) =>
|
||||
{
|
||||
res.SetStatus(200).SetBytes("Hello! This is a second test!");
|
||||
}));
|
||||
|
||||
http.Handlers.Add(new HTTPServeFileHandler("/favicon.ico", "favicon.ico",GetMimeType("ico")));*/
|
||||
|
||||
http.Listen();
|
||||
|
||||
}
|
||||
|
||||
private static string GetStatusFromNum(int v)
|
||||
{
|
||||
return v switch
|
||||
{
|
||||
200 => "200 OK",
|
||||
400 => "400 Bad Request",
|
||||
401 => "401 Unauthorized",
|
||||
403 => "403 Forbidden",
|
||||
404 => "404 Not Found",
|
||||
_ => "501 Not Implemented"
|
||||
};
|
||||
}
|
||||
private static string GetMimeType(string v)
|
||||
{
|
||||
/*
|
||||
image/apng: Animated Portable Network Graphics (APNG)
|
||||
image/avif : AV1 Image File Format (AVIF)
|
||||
image/gif: Graphics Interchange Format (GIF)
|
||||
image/jpeg: Joint Photographic Expert Group image (JPEG)
|
||||
image/png: Portable Network Graphics (PNG)
|
||||
image/svg+xml: Scalable Vector Graphics (SVG)
|
||||
image/webp: Web Picture format (WEBP)
|
||||
*/
|
||||
return v switch
|
||||
{
|
||||
// text
|
||||
"txt" => "text/plain",
|
||||
"css" => "text/css",
|
||||
"js" => "text/javascript",
|
||||
"html" => "text/html",
|
||||
"json" => "application/json",
|
||||
// image
|
||||
"webp" => "image/webp",
|
||||
"png" => "image/png",
|
||||
"jpg" or "jpeg" => "image/jpeg",
|
||||
"svg" => "image/svg+xml",
|
||||
"gif" => "image/gif",
|
||||
"ico" => "image/x-icon",
|
||||
// just download it man
|
||||
_ => "application/octet-stream"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
10
myownhttp.csproj
Normal file
10
myownhttp.csproj
Normal file
@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
25
myownhttp.sln
Normal file
25
myownhttp.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36203.30 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "myownhttp", "myownhttp.csproj", "{4E977172-6187-481D-B819-982A278D925E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4E977172-6187-481D-B819-982A278D925E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4E977172-6187-481D-B819-982A278D925E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4E977172-6187-481D-B819-982A278D925E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E977172-6187-481D-B819-982A278D925E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FB36ECD5-0874-4AB9-A8BB-2AF5DE85A8F9}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Loading…
Reference in New Issue
Block a user