HS Codebank Article
Back
Webserver Class

Author: Guitarman 04/15/2021
Language: C#
Views: 69


Description:

This is a simple http webserver class I found years ago.

Article:

I used this in a small file server I built some years back.

Full Source Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace HS_WebServer
{
    public class HS_Web_Server
    {
        /// <summary>
        /// To see a file list with links use /* as the file name
        /// </summary>
        public bool AllowFileList { get; set; } = false;
        /// <summary>
        /// Defaults = "index.html, index.htm, default.html, and default.htm
        /// </summary>
        public string[] _indexFiles = {
        "index.html",
        "index.htm",
        "default.html",
        "default.htm"
        };
        /// <summary>
        /// Check if the server has started
        /// </summary>
        public bool IsServerRunning { get; set; } = false;

        //public event CurrentFile_EventHandler CurrentFile;
        //public delegate void CurrentFile_EventHandler(string CF);

        /// <summary>
        /// IDictionary mime types
        /// </summary>
        public IDictionary<string, string> _mimeTypeMappings = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) {
        #region extension to MIME type list
        {".asf", "video/x-ms-asf"},
        {".asx", "video/x-ms-asf"},
        {".avi", "video/x-msvideo"},
        {".bin", "application/octet-stream"},
        {".cco", "application/x-cocoa"},
        {".crt", "application/x-x509-ca-cert"},
        {".css", "text/css"},
        {".deb", "application/octet-stream"},
        {".der", "application/x-x509-ca-cert"},
        {".dll", "application/octet-stream"},
        {".dmg", "application/octet-stream"},
        {".ear", "application/java-archive"},
        {".eot", "application/octet-stream"},
        {".exe", "application/octet-stream"},
        {".flv", "video/x-flv"},
        {".gif", "image/gif"},
        {".hqx", "application/mac-binhex40"},
        {".htc", "text/x-component"},
        {".htm", "text/html"},
        {".html", "text/html"},
        {".ico", "image/x-icon"},
        {".img", "application/octet-stream"},
        {".iso", "application/octet-stream"},
        {".jar", "application/java-archive"},
        {".jardiff", "application/x-java-archive-diff"},
        {".jng", "image/x-jng"},
        {".jnlp", "application/x-java-jnlp-file"},
        {".jpeg", "image/jpeg"},
        {".jpg", "image/jpeg"},
        {".js", "application/x-javascript"},
        {".mml", "text/mathml"},
        {".mng", "video/x-mng"},
        {".mov", "video/quicktime"},
        {".mp3", "audio/mpeg"},
        {".mpeg", "video/mpeg"},
        {".mpg", "video/mpeg"},
        {".mp4", "video/mp4"},
        {".msi", "application/octet-stream"},
        {".msm", "application/octet-stream"},
        {".msp", "application/octet-stream"},
        {".pdb", "application/x-pilot"},
        {".pdf", "application/pdf"},
        {".pem", "application/x-x509-ca-cert"},
        {".pl", "application/x-perl"},
        {".pm", "application/x-perl"},
        {".png", "image/png"},
        {".prc", "application/x-pilot"},
        {".ra", "audio/x-realaudio"},
        {".rar", "application/x-rar-compressed"},
        {".rpm", "application/x-redhat-package-manager"},
        {".rss", "text/xml"},
        {".run", "application/x-makeself"},
        {".sea", "application/x-sea"},
        {".shtml", "text/html"},
        {".sit", "application/x-stuffit"},
        {".swf", "application/x-shockwave-flash"},
        {".tcl", "application/x-tcl"},
        {".tk", "application/x-tcl"},
        {".txt", "text/plain"},
        {".war", "application/java-archive"},
        {".wbmp", "image/vnd.wap.wbmp"},
        {".wmv", "video/x-ms-wmv"},
        {".xml", "text/xml"},
        {".xpi", "application/x-xpinstall"},
        {".zip", "application/zip"},
        #endregion
        };

        private Thread _serverThread;
        private string _rootDirectory;
        private HttpListener _listener;
        private int _port;

        public int Port
        {
            get { return _port; }
            private set { }
        }

        /// <summary>
        /// Construct server with given port.
        /// </summary>
        /// <param name="RootFolder">Directory path to serve.</param>
        /// <param name="port">Server port number.</param>
        public HS_Web_Server(string RootFolder, int port)
        {
            this.Initialize(RootFolder, port);
            IsServerRunning = true;
        }

        /// <summary>
        /// Construct server with suitable port.
        /// </summary>
        /// <param name="path">Directory path to serve.</param>
        public HS_Web_Server(string RootFolder)
        {
            //get an empty port
            TcpListener l = new TcpListener(IPAddress.Loopback, 0);
            l.Start();
            int port = ((IPEndPoint)l.LocalEndpoint).Port;
            l.Stop();
            this.Initialize(RootFolder, port);
            IsServerRunning = true;
        }

        /// <summary>
        /// Stop server and dispose all functions.
        /// </summary>
        public void Stop()
        {
            _serverThread.Abort();
            _listener.Stop();
            IsServerRunning = false;
        }

        private void Listen()
        {
            _listener = new HttpListener();
            //_listener.Prefixes.Add("http://127.0.0.1:" + _port.ToString() + "/");
            _listener.Prefixes.Add("http://localhost:" + _port.ToString() + "/");
            //_listener.Prefixes.Add("http://+:" + _port.ToString() + "/");
            //_listener.IgnoreWriteExceptions = true;
            _listener.Start();
            while (true)
            {
                try
                {
                    HttpListenerContext context = _listener.GetContext();
                    Process(context);
                }
                catch (Exception)
                {

                }
            }
        }

        private void Process(HttpListenerContext context)
        {
            string filename = context.Request.Url.AbsolutePath;
            //Console.WriteLine(filename);
            //CurrentFile.Invoke(filename);
            filename = filename.Substring(1);

            //file list
            if (filename == "*" && AllowFileList == true)
            {
                try
                {
                    int FileCount = 0;
                    string FileList = null;
                    FileList += "<strong>File List</strong>";
                    FileList += "<hr/>";
                    DirectoryInfo di = new DirectoryInfo(_rootDirectory);
                    foreach (var item in di.GetFiles(@"*.*", SearchOption.AllDirectories))
                    {
                        string vPath = item.FullName.Replace(_rootDirectory, "").Replace(@"\", "/");
                        FileCount += 1;
                        FileList += "<strong>" + FileCount + ": " + "</strong>" + "<a href='" + vPath + "'>" + item.Name + "</a>" + "<br/>";
                    }

                    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(FileList);
                    context.Response.ContentLength64 = buffer.Length;
                    Stream output = context.Response.OutputStream;
                    output.Write(buffer, 0, buffer.Length);

                    context.Response.StatusCode = (int)HttpStatusCode.OK;
                    context.Response.OutputStream.Flush();
                }
                catch
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                }
            }

            //Json file list
            //if (filename == "json*" && AllowJsonFileList == true)
            //{
            //    try
            //    {
            //        string responseString = JsonConvert.SerializeObject(Directory.GetFiles(_rootDirectory, @"*.*", SearchOption.AllDirectories));
            //        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
            //        context.Response.ContentLength64 = buffer.Length;
            //        Stream output = context.Response.OutputStream;
            //        output.Write(buffer, 0, buffer.Length);

            //        context.Response.StatusCode = (int)HttpStatusCode.OK;
            //        context.Response.OutputStream.Flush();
            //    }
            //    catch
            //    {
            //        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            //    }
            //}

            if (string.IsNullOrEmpty(filename))
            {
                foreach (string indexFile in _indexFiles)
                {
                    if (File.Exists(Path.Combine(_rootDirectory, indexFile)))
                    {
                        filename = indexFile;
                        break;
                    }
                }
            }

            filename = Path.Combine(_rootDirectory, filename);

            if (File.Exists(filename))
            {
                try
                {
                    using (Stream input = new FileStream(filename, FileMode.Open)) //Stream input = new FileStream(filename, FileMode.Open);
                    {
                        //Adding permanent http response headers
                        string mime;
                        context.Response.ContentType = _mimeTypeMappings.TryGetValue(Path.GetExtension(filename), out mime) ? mime : "application/octet-stream";
                        context.Response.ContentLength64 = input.Length;
                        context.Response.AddHeader("Date", DateTime.Now.ToString("r"));
                        context.Response.AddHeader("Last-Modified", System.IO.File.GetLastWriteTime(filename).ToString("r"));

                        if (context.Request.HttpMethod != "HEAD")
                        {
                            byte[] buffer = new byte[1024 * 16];
                            int nbytes;
                            while ((nbytes = input.Read(buffer, 0, buffer.Length)) > 0)
                                context.Response.OutputStream.Write(buffer, 0, nbytes);
                        }
                        input.Close();
                    }

                    context.Response.StatusCode = (int)HttpStatusCode.OK;
                    context.Response.OutputStream.Flush();
                }
                catch (Exception)
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                }

            }
            else
            {
                context.Response.StatusCode = (int)HttpStatusCode.NotFound;
            }

            context.Response.OutputStream.Close();
        }

        private void Initialize(string path, int port)
        {
            this._rootDirectory = path;
            this._port = port;
            _serverThread = new Thread(this.Listen)
            {
                IsBackground = true
            };
            _serverThread.Start();
        }
    }
}

Back
Comments
There are no comments yet.