view 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 source

???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; }
	}
}