Blog / Home
About
Media Gallery

Welcome
to
Thronic.com

ժʝ_

HttpListener() Example


The following sample code is a roughly edited and stripped down excerpt from a server class I wrote. Exception handling and a lot of extra data handling has been removed and names made a little more generic, to provide the idea of how to set up a basic server that can be built upon. I included some basic file handling and HTML returns and querystring parsing as well.

class WebServer
{
	HttpListener Listener = new HttpListener();
	public bool IsRunning {get; private set;}
	private string PORT;

	public void Start(string PORT, Form1 MainForm)
	{
		if (PORT == "")
			return;

		// Supported on current OS?
		if (!HttpListener.IsSupported) {
			MessageBox.Show("This OS is too old.","Sorry",MessageBoxButtons.OK,MessageBoxIcon.Hand);
			Environment.Exit(1);
			return;
		}

		// Set things up for starting.
		this.PORT = PORT;

		// Start hovedmotoren (main loop).
		Thread T = new Thread(new ThreadStart(WebMainLoop));
		T.IsBackground = true;
		T.Start();
	}

	private void WebMainLoop()
	{
		Listener.Prefixes.Add("http://+:"+ PORT +"/");
		Listener.Start();
		IsRunning = true;
		IAsyncResult AsyncResult;

		while (IsRunning) {
			// Wait for requests, then kick them off in their own thread.
			AsyncResult = Listener.BeginGetContext(new AsyncCallback(WebDoorman),Listener);
			AsyncResult.AsyncWaitHandle.WaitOne();
		}

		// Stop() called, it lets the current iteration complete, 
		// we then stop the listener here once loop is broken.
		Listener.Stop();
		Listener.Prefixes.Clear();
	}
	
	private void WebDoorman(IAsyncResult result)
	{
			// Receiving work as a callback function, reporting back.
			HttpListener DoormanListener = (HttpListener)result.AsyncState;
			HttpListenerContext context = DoormanListener.EndGetContext(result);

			// Thread started, Listener is ready for new requests.
			string ourHTML = "";
			byte[] SendBackBuffer;
			Stream SendStream;
			string FullFileUrl = "";
			int BytesRead = 0;

			/* Checking for GET data
			foreach (string _qsi in context.Request.QueryString.AllKeys) {
				// _qsi gives the key name.
				// context.Request.QueryString[_qsi] gives the key value. (?key=val)
			}
			
			// Is it a specific file that's requested?
			if (
				context.Request.RawUrl.Contains(".png") ||
				context.Request.RawUrl.Contains(".jpg") || 
				context.Request.RawUrl.Contains(".gif") || 
				context.Request.RawUrl.Contains(".ico") || 
				context.Request.RawUrl.Contains(".css") || 
				context.Request.RawUrl.Contains(".js")
			) {
				FullFileUrl = "somefolder" + context.Request.RawUrl.Replace('/','\\');
				FullFileUrl = FullFileUrl.Split('?')[0];

				if (FullFileUrl.Contains(".png"))
					context.Response.ContentType = "image/png";
				else if (FullFileUrl.Contains(".jpg"))
					context.Response.ContentType = "image/jpeg";
				else if (FullFileUrl.Contains(".gif"))
					context.Response.ContentType = "image/gif";
				else if (FullFileUrl.Contains(".css"))
					context.Response.ContentType = "text/css";
				else if (FullFileUrl.Contains(".js"))
					context.Response.ContentType = "text/javascript";
				else if (FullFileUrl.Contains(".ico"))
					context.Response.ContentType = "image/x-icon";

				if (File.Exists(FullFileUrl)) {
					using (FileStream fs = File.OpenRead(FullFileUrl)) {
						context.Response.ContentLength64 = fs.Length;
						SendStream = context.Response.OutputStream;
						SendBackBuffer = new byte[64 * 1024]; // Send in 64 KB chunks.
						while ((BytesRead = fs.Read(SendBackBuffer,0,SendBackBuffer.Length)) > 0) {
							SendStream.Write(SendBackBuffer,0,BytesRead);
						}
						SendStream.Close();
					}
					return;
				} else {
					context.Response.StatusCode = 404;
					ourHTML =  missing();
					
					SendBackBuffer = Encoding.UTF8.GetBytes(ourHTML);
					context.Response.ContentLength64 = SendBackBuffer.Length;
					context.Response.ContentType = "text/html";
					SendStream = context.Response.OutputStream;
					SendStream.Write(SendBackBuffer,0,SendBackBuffer.Length);
					SendStream.Close();
				}
			}

			// A HTML page
			if (context.Request.RawUrl.Contains("page1")) {
				ourHTML = HtmlSkeleton(context.Request.UserAgent,"page1.css","") + 
				page1();

				SendBackBuffer = Encoding.UTF8.GetBytes(ourHTML);
				context.Response.ContentLength64 = SendBackBuffer.Length;
				context.Response.ContentType = "text/html";
				SendStream = context.Response.OutputStream;
				SendStream.Write(SendBackBuffer,0,SendBackBuffer.Length);
				SendStream.Close();
				return;
			}

			// Another HTML page
			if (context.Request.RawUrl.Contains("page2")) {
				ourHTML = HtmlSkeleton(context.Request.UserAgent,"page2.css","page2.js") + 
				page2();

				SendBackBuffer = Encoding.UTF8.GetBytes(ourHTML);
				context.Response.ContentLength64 = SendBackBuffer.Length;
				context.Response.ContentType = "text/html";
				SendStream = context.Response.OutputStream;
				SendStream.Write(SendBackBuffer,0,SendBackBuffer.Length);
				SendStream.Close();
				return;
			}

			// Standard tilbakemelding hvis ingen andre aksjoner har blitt oppfanget.
			ourHTML = HtmlSkeleton(context.Request.UserAgent,"","") + 
			"WebServer Default Page."+
			"</body></html>";
			SendBackBuffer = Encoding.UTF8.GetBytes(ourHTML);
			context.Response.ContentLength64 = SendBackBuffer.Length;
			SendStream = context.Response.OutputStream;
			SendStream.Write(SendBackBuffer,0,SendBackBuffer.Length);
			SendStream.Close();

			/*
			 * Only care about errors if we're not shutting down. 
			 * Certain exceptions will be thrown regardless because of web clients 
			 * having orphaned AJAX calls and/or connections being broken from server 
			 * (i.e. restarts). We filter out the ones we experience during testing.
			 * 					
				if (
					!e.ToString().Contains("System.Net.HttpResponseStream.Write") && 
					!e.ToString().Contains("System.NullReferenceException") && 
					!e.ToString().Contains("System.ObjectDisposedException")
				)
					// handle
			*/
	}

	private string page1()
	{
		string ReturnString = "<div id=\"Main\">";
		// do content...
		ReturnString += "</div>";
		return "</body></html>"+ ReturnString;
	}

	private string page2()
	{
		string ReturnString = "<div id=\"Main\">";
		// do content...
		ReturnString += "</div>";
		return "</body></html>"+ ReturnString;
	}

	public bool IsListening()
	{
		return Listener.IsListening;
	}

	private string Missing()
	{
		return "<!doctype html>"+
		"<html>"+
		"<head>"+
		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"+
		"<link href=\"/CSS/missing.css\" rel=\"stylesheet\" type=\"text/css\">"+
		"<title>Oops</title>"+
		"</head>"+
		"<body>"+
		"<img src=\"/images/404.png\"><br>"+
		"404 - This link does not exist.<br><br>"+
		"</body>"+
		"</html>";
	}

	private string HtmlSkeleton(string UserAgent, string cssCustomFile, string jsCustomFile)
	{
		string DocType = "<!doctype html>";
		string cssFileName = "main.css";
		string jsFileName = "main.js";
		
		string HTML = ""+
		"<html>"+
		"<head>"+
		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"+
		"<link rel=\"shortcut icon\" href=\"/Images/favicon.ico\" type=\"image/x-icon\">"+
		"<link href=\"/CSS/"+ (cssCustomFile!=""?cssCustomFile:cssFileName) +" rel=\"stylesheet\" type=\"text/css\">"+
		"<script src=\"/JS/"+ (jsCustomFile!=""?jsCustomFile:jsFileName) +" type=\"text/javascript\"></script>"+
		"<title>MyWebServer</title>";

		// do content...

		HTML +=""+
		"</head>"+
		"<body>";

		return DocType + HTML;
	}

	public void Stop()
	{
		IsRunning = false;

		try {
		// Trigger a nonsense call to shut down any loop blocking listener.
		WebRequest webRequest = WebRequest.Create("http://127.0.0.1:" + PORT);
		WebResponse webResponse = webRequest.GetResponse();
		} catch (Exception) {}
	}
}



Original Post: Jan 27th, '22 20:26 CET.

C#
π