using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
var ipep = new IPEndPoint(IPAddress.Any, 80);
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(ipep);
server.Listen(100);
#if DEBUG
if(Env.OSVersion.Platform == PlatformID.Win32NT)
{
Process.Start("explorer", "http://localhost/test/param.html");
}
#endif
WriteLine("Port " + ipep.Port + " listening");
while (true)
{
Socket client = server.Accept();
Task.Run(() => newWork(client)); //자식 스레드에 인계
}
static void newWork(Socket client)
{
Request req = null;
try
{
client.ReceiveTimeout = 5000; //최대 5초 기다려줌을 선언
req = new Request(client);
Func<bool> trouble = (!client.Connected || req.Count is 0, req.err) switch
{
(true , _ ) => () => { WriteLine("Disconnected: by client"); return true; },
( _ , null) => () => { WriteLine(req.First().Value); return false; },
( _ ,var _) => () => { resForbadrequest(client, req.err); return true; }
};
if(trouble()) return;
WriteLine("hello~ " + (req.nickname ?? "newbie"));
if (req.url == "/") req.url = "/index.html";
response(req);
}
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
{
WriteLine("Disconnected: timeout");
}
catch (Exception ex)
{
WriteLine(ex);
}
finally
{
WriteLine("bye~ " + (req?.nickname ?? "anonymous"));
client.Close();
client.Dispose();
}
}
static void response(Request req)
{
string publicPath = Path.Combine(Util.sPath, "public");
Socket client = req.client;
Ftag ftag = Util.getFInfo(publicPath + req.url);
FileInfo info = ftag.info;
if (!info.Exists || !info.FullName.StartsWith(publicPath))
{
resForbadrequest(client, "404 Not found");
return;
}
var sb = new StringBuilder(100);
bool m = ftag.etag == req.GetD("If-None-Match");
sb.AddL($"HTTP/1.1 {(m ? "304 Not Modified" : "200 ok")}");
sb.AddL("Accept-Ranges: none");
sb.AddL("Cache-Control: public, max-age=0");
sb.AddL("Last-Modified: " + ftag.modiTime);
sb.AddL("Etag: " + ftag.etag);
sb.AddL("Date: " + Util.uTime);
if(!m)
{
sb.AddL("Content-type: " + ftag.minetype);
sb.AddL("Content-Length: " + info.Length);
}
sb.AddL("Server: test server");
sb.AddL("Connection: close");
if (req.sessionID == null)
{
sb.AddL("set-cookie: sessionID=" + req.newSessionID() + "; path=/; httponly");
}
sb.AddL();
client.Send(Encoding.UTF8.GetBytes(sb.ToString()));
if (!m) client.Send(File.ReadAllBytes(info.FullName));
}
static void resForbadrequest(Socket client, string msg)
{
var sb = new StringBuilder(100);
sb.AddL("HTTP/1.1 400 Bad Request");
sb.AddL("date: " + Util.uTime);
sb.AddL("Server: test server");
sb.AddL("Content-type:text/plain; charset=UTF-8");
sb.AddL("Content-Length: " + msg.Length);
sb.AddL("Connection: close");
sb.AddL();
sb.AddL(msg);
client.Send(Encoding.UTF8.GetBytes(sb.ToString()));
}