Mercurial > hg > ucis.core
diff Net/HTTP.cs @ 0:3ab940a0c7a0
Initial commit
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Tue, 11 Sep 2012 16:28:53 +0200 |
parents | |
children | 0cc7be03775f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Net/HTTP.cs Tue Sep 11 16:28:53 2012 +0200 @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +namespace UCIS.Net.HTTP { + public class HTTPServer : TCPServer.IModule { + public Dictionary<string, HTTPContent> Content = new Dictionary<string, HTTPContent>(StringComparer.InvariantCultureIgnoreCase); + public HTTPContent DefaultContent = null; + + public bool Accept(TCPStream Stream) { + StreamReader StreamReader = new StreamReader(Stream, Encoding.ASCII); + String Line = StreamReader.ReadLine(); + String[] Request = Line.Split(' '); + + //Console.WriteLine("HTTP.Server.Accept Request: " + Line); + + if (Request == null || Request.Length < 2 || Request[0] != "GET" || Request[1][0] != '/') { + //Console.WriteLine("HTTP.Server.Start Bad request"); + SendError(Stream, 400); + return true; + } + + Request = Request[1].Split(new Char[] { '?' }, 2); + HTTPContent content; + if (Content.TryGetValue(Request[0], out content)) { + } else if (DefaultContent != null) { + content = DefaultContent; + } else { + SendError(Stream, 404); + return true; + } + HTTPContext Context = new HTTPContext(); + Context.Stream = Stream; + Context.Request = new HTTPRequest(); + Context.Request.Method = Method.GET; + Context.Request.Path = Request[0]; + if (Request.Length == 2) { + Context.Request.Query = Request[1]; + } else { + Context.Request.Query = null; + } + HTTPContent.Result ServeResult = content.Serve(Context); + + if (ServeResult == HTTPContent.Result.OK_KEEPALIVE) { + return false; + } else if (!(ServeResult == HTTPContent.Result.OK_CLOSE)) { + SendError(Stream, (int)ServeResult); + } + return true; + } + + public static void SendError(Stream Stream, int ErrorCode) { + string ErrorText = null; + switch (ErrorCode) { + case 400: + ErrorText = "The request could not be understood by the server due to malformed syntax."; + break; + case 404: + ErrorText = "The requested file can not be found."; + break; + default: + ErrorText = "Unknown error code: " + ErrorCode.ToString() + "."; + break; + } + SendHeader(Stream, ErrorCode, "text/plain", ErrorText.Length); + WriteLine(Stream, ErrorText); + Thread.Sleep(100); + return; + } + + public static void SendHeader(Stream Stream, int ResultCode, string ContentType) { + SendHeader(Stream, ResultCode, ContentType, -1); + } + public static void SendHeader(Stream Stream, int ResultCode, string ContentType, int ContentLength) { + //ResultCode = 200, ContentType = null, ContentLength = -1 + string ResultString; + switch (ResultCode) { + case 200: ResultString = "OK"; break; + case 400: ResultString = "Bad Request"; break; + case 404: ResultString = "Not found"; break; + default: ResultString = "Unknown"; break; + } + WriteLine(Stream, "HTTP/1.1 " + ResultCode.ToString() + " " + ResultString); + WriteLine(Stream, "Expires: Mon, 26 Jul 1990 05:00:00 GMT"); + WriteLine(Stream, "Cache-Control: no-store, no-cache, must-revalidate"); + WriteLine(Stream, "Cache-Control: post-check=0, pre-check=0"); + WriteLine(Stream, "Pragma: no-cache"); + WriteLine(Stream, "Server: UCIS Simple Webserver"); + WriteLine(Stream, "Connection: Close"); + if ((ContentType != null)) WriteLine(Stream, "Content-Type: " + ContentType); + if (ContentLength != -1) WriteLine(Stream, "Content-Length: " + ContentLength.ToString()); + WriteLine(Stream, ""); + } + + public static void WriteLine(Stream Stream, string Line) { + byte[] Buffer = null; + Buffer = Encoding.ASCII.GetBytes(Line); + Stream.Write(Buffer, 0, Buffer.Length); + Stream.WriteByte(13); + Stream.WriteByte(10); + } + } + + public abstract class HTTPContent { + public abstract Result Serve(HTTPContext Context); + public enum Result : int { + OK_CLOSE = -2, + OK_KEEPALIVE = -1, + ERR_NOTFOUND = 404 + } + } + + public class HTTPFileContent : HTTPContent { + public string Filename { get; private set; } + public string ContentType { get; private set; } + + public HTTPFileContent(string Filename) : this(Filename, "application/octet-stream") { } + public HTTPFileContent(string Filename, string ContentType) { + this.Filename = Filename; + this.ContentType = ContentType; + } + + public override Result Serve(HTTPContext Context) { + if (!File.Exists(Filename)) return Result.ERR_NOTFOUND; + + using (FileStream FileStream = File.OpenRead(Filename)) { + HTTPServer.SendHeader(Context.Stream, 200, ContentType, (int)FileStream.Length); + byte[] Buffer = new byte[1025]; + while (FileStream.CanRead) { + int Length = FileStream.Read(Buffer, 0, Buffer.Length); + if (Length <= 0) break; + Context.Stream.Write(Buffer, 0, Length); + } + } + return Result.OK_CLOSE; + } + } + + public class HTTPContext { + public HTTPRequest Request { get; internal set; } + public TCPStream Stream { get; internal set; } + } + + public enum Method { + GET = 0, + HEAD = 1, + POST = 2, + PUT = 3 + } + + public class HTTPRequest { + public HTTP.Method Method { get; internal set; } + public string Path { get; internal set; } + public string Query { get; internal set; } + } +}