Index: binary-improvements2/MapRendering/Web/API/AbsWebAPI.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/AbsWebAPI.cs	(revision 387)
+++ binary-improvements2/MapRendering/Web/API/AbsWebAPI.cs	(revision 387)
@@ -0,0 +1,15 @@
+namespace AllocsFixes.NetConnections.Servers.Web.API {
+	public abstract class AbsWebAPI {
+		public readonly string Name;
+
+		protected AbsWebAPI (string _name = null) {
+			Name = _name ?? GetType ().Name;
+		}
+
+		public abstract void HandleRequest (RequestContext _context);
+
+		public virtual int DefaultPermissionLevel () {
+			return 0;
+		}
+	}
+}
Index: binary-improvements2/MapRendering/Web/API/ExecuteConsoleCommand.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/ExecuteConsoleCommand.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/ExecuteConsoleCommand.cs	(revision 387)
@@ -1,25 +1,21 @@
 using System;
 using System.Net;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class ExecuteConsoleCommand : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
-			if (string.IsNullOrEmpty (_req.QueryString ["command"])) {
-				_resp.StatusCode = (int) HttpStatusCode.BadRequest;
-				Web.SetResponseTextContent (_resp, "No command given");
+	public class ExecuteConsoleCommand : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
+			if (string.IsNullOrEmpty (_context.Request.QueryString ["command"])) {
+				WebUtils.WriteText (_context.Response, "No command given", HttpStatusCode.BadRequest);
 				return;
 			}
 
 			WebCommandResult.ResultType responseType =
-				_req.QueryString ["raw"] != null
+				_context.Request.QueryString ["raw"] != null
 					? WebCommandResult.ResultType.Raw
-					: (_req.QueryString ["simple"] != null
+					: (_context.Request.QueryString ["simple"] != null
 						? WebCommandResult.ResultType.ResultOnly
 						: WebCommandResult.ResultType.Full);
 
-			string commandline = _req.QueryString ["command"];
+			string commandline = _context.Request.QueryString ["command"];
 			string commandPart = commandline.Split (' ') [0];
 			string argumentsPart = commandline.Substring (Math.Min (commandline.Length, commandPart.Length + 1));
@@ -28,6 +24,5 @@
 
 			if (command == null) {
-				_resp.StatusCode = (int) HttpStatusCode.NotFound;
-				Web.SetResponseTextContent (_resp, "Unknown command");
+				WebUtils.WriteText (_context.Response, "Unknown command", HttpStatusCode.NotFound);
 				return;
 			}
@@ -35,12 +30,11 @@
 			int commandPermissionLevel = GameManager.Instance.adminTools.GetCommandPermissionLevel (command.GetCommands ());
 
-			if (_permissionLevel > commandPermissionLevel) {
-				_resp.StatusCode = (int) HttpStatusCode.Forbidden;
-				Web.SetResponseTextContent (_resp, "You are not allowed to execute this command");
+			if (_context.PermissionLevel > commandPermissionLevel) {
+				WebUtils.WriteText (_context.Response, "You are not allowed to execute this command", HttpStatusCode.Forbidden);
 				return;
 			}
 
-			_resp.SendChunked = true;
-			WebCommandResult wcr = new WebCommandResult (commandPart, argumentsPart, responseType, _resp);
+			_context.Response.SendChunked = true;
+			WebCommandResult wcr = new WebCommandResult (commandPart, argumentsPart, responseType, _context.Response);
 			SdtdConsole.Instance.ExecuteAsync (commandline, wcr);
 		}
Index: binary-improvements2/MapRendering/Web/API/GetAllowedCommands.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetAllowedCommands.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetAllowedCommands.cs	(revision 387)
@@ -1,15 +1,12 @@
 using AllocsFixes.JSON;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetAllowedCommands : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetAllowedCommands : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			JSONObject result = new JSONObject ();
 			JSONArray entries = new JSONArray ();
 			foreach (IConsoleCommand cc in SdtdConsole.Instance.GetCommands ()) {
 				int commandPermissionLevel = GameManager.Instance.adminTools.GetCommandPermissionLevel (cc.GetCommands ());
-				if (_permissionLevel <= commandPermissionLevel) {
+				if (_context.PermissionLevel <= commandPermissionLevel) {
 					string cmd = string.Empty;
 					foreach (string s in cc.GetCommands ()) {
@@ -29,5 +26,5 @@
 			result.Add ("commands", entries);
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 
Index: binary-improvements2/MapRendering/Web/API/GetAnimalsLocation.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetAnimalsLocation.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetAnimalsLocation.cs	(revision 387)
@@ -2,13 +2,10 @@
 using AllocsFixes.JSON;
 using AllocsFixes.LiveData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	internal class GetAnimalsLocation : WebAPI {
+	internal class GetAnimalsLocation : AbsWebAPI {
 		private readonly List<EntityAnimal> animals = new List<EntityAnimal> ();
 
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+		public override void HandleRequest (RequestContext _context) {
 			JSONArray animalsJsResult = new JSONArray ();
 
@@ -37,5 +34,5 @@
 			}
 
-			WriteJSON (_resp, animalsJsResult);
+			WebUtils.WriteJson (_context.Response, animalsJsResult);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetHostileLocation.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetHostileLocation.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetHostileLocation.cs	(revision 387)
@@ -2,13 +2,10 @@
 using AllocsFixes.JSON;
 using AllocsFixes.LiveData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	internal class GetHostileLocation : WebAPI {
+	internal class GetHostileLocation : AbsWebAPI {
 		private readonly List<EntityEnemy> enemies = new List<EntityEnemy> ();
 
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+		public override void HandleRequest (RequestContext _context) {
 			JSONArray hostilesJsResult = new JSONArray ();
 
@@ -37,5 +34,5 @@
 			}
 
-			WriteJSON (_resp, hostilesJsResult);
+			WebUtils.WriteJson (_context.Response, hostilesJsResult);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetLandClaims.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetLandClaims.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetLandClaims.cs	(revision 387)
@@ -3,16 +3,12 @@
 using AllocsFixes.JSON;
 using AllocsFixes.PersistentData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetLandClaims : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetLandClaims : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			PlatformUserIdentifierAbs requestedUserId = null;
-			if (_req.QueryString ["userid"] != null) {
-				if (!PlatformUserIdentifierAbs.TryFromCombinedString (_req.QueryString ["userid"], out requestedUserId)) {
-					_resp.StatusCode = (int) HttpStatusCode.BadRequest;
-					Web.SetResponseTextContent (_resp, "Invalid user id given");
+			if (_context.Request.QueryString ["userid"] != null) {
+				if (!PlatformUserIdentifierAbs.TryFromCombinedString (_context.Request.QueryString ["userid"], out requestedUserId)) {
+					WebUtils.WriteText (_context.Response, "Invalid user id given", HttpStatusCode.BadRequest);
 					return;
 				}
@@ -20,7 +16,7 @@
 
 			// default user, cheap way to avoid 'null reference exception'
-			PlatformUserIdentifierAbs userId = _user?.UserId;
+			PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
 
-			bool bViewAll = WebConnection.CanViewAllClaims (_permissionLevel);
+			bool bViewAll = WebConnection.CanViewAllClaims (_context.PermissionLevel);
 
 			JSONObject result = new JSONObject ();
@@ -74,5 +70,5 @@
 			}
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetLog.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetLog.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetLog.cs	(revision 387)
@@ -1,14 +1,11 @@
 using System.Collections.Generic;
 using AllocsFixes.JSON;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetLog : WebAPI {
+	public class GetLog : AbsWebAPI {
 		private const int MAX_COUNT = 1000;
 		
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
-			if (_req.QueryString ["count"] == null || !int.TryParse (_req.QueryString ["count"], out int count)) {
+		public override void HandleRequest (RequestContext _context) {
+			if (_context.Request.QueryString ["count"] == null || !int.TryParse (_context.Request.QueryString ["count"], out int count)) {
 				count = 50;
 			}
@@ -26,5 +23,5 @@
 			}
 
-			if (_req.QueryString ["firstLine"] == null || !int.TryParse (_req.QueryString ["firstLine"], out int firstLine)) {
+			if (_context.Request.QueryString ["firstLine"] == null || !int.TryParse (_context.Request.QueryString ["firstLine"], out int firstLine)) {
 				firstLine = count > 0 ? LogBuffer.Instance.OldestLine : LogBuffer.Instance.LatestLine;
 			}
@@ -37,6 +34,4 @@
 			foreach (LogBuffer.LogEntry logEntry in logEntries) {
 				JSONObject entry = new JSONObject ();
-				entry.Add ("date", new JSONString (logEntry.date));
-				entry.Add ("time", new JSONString (logEntry.time));
 				entry.Add ("isotime", new JSONString (logEntry.isoTime));
 				entry.Add ("uptime", new JSONString (logEntry.uptime.ToString ()));
@@ -51,5 +46,5 @@
 			result.Add ("entries", entries);
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetPlayerInventories.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetPlayerInventories.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetPlayerInventories.cs	(revision 387)
@@ -2,12 +2,9 @@
 using AllocsFixes.JSON;
 using AllocsFixes.PersistentData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetPlayerInventories : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
-			GetPlayerInventory.GetInventoryArguments (_req, out bool showIconColor, out bool showIconName);
+	public class GetPlayerInventories : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
+			GetPlayerInventory.GetInventoryArguments (_context.Request, out bool showIconColor, out bool showIconName);
 
 			JSONArray AllInventoriesResult = new JSONArray ();
@@ -25,5 +22,5 @@
 			}
 
-			WriteJSON (_resp, AllInventoriesResult);
+			WebUtils.WriteJson (_context.Response, AllInventoriesResult);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetPlayerInventory.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetPlayerInventory.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetPlayerInventory.cs	(revision 387)
@@ -4,20 +4,16 @@
 using AllocsFixes.PersistentData;
 using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetPlayerInventory : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp,
-			WebConnection _user, int _permissionLevel) {
-			if (_req.QueryString ["userid"] == null) {
-				_resp.StatusCode = (int) HttpStatusCode.BadRequest;
-				Web.SetResponseTextContent (_resp, "No user id given");
+	public class GetPlayerInventory : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
+			if (_context.Request.QueryString ["userid"] == null) {
+				WebUtils.WriteText (_context.Response, "No user id given", HttpStatusCode.BadRequest);
 				return;
 			}
 
-			string userIdString = _req.QueryString ["userid"];
+			string userIdString = _context.Request.QueryString ["userid"];
 			if (!PlatformUserIdentifierAbs.TryFromCombinedString (userIdString, out PlatformUserIdentifierAbs userId)) {
-				_resp.StatusCode = (int) HttpStatusCode.BadRequest;
-				Web.SetResponseTextContent (_resp, "Invalid user id given");
+				WebUtils.WriteText (_context.Response, "Invalid user id given", HttpStatusCode.BadRequest);
 				return;
 			}
@@ -25,14 +21,13 @@
 			Player p = PersistentContainer.Instance.Players [userId, false];
 			if (p == null) {
-				_resp.StatusCode = (int) HttpStatusCode.NotFound;
-				Web.SetResponseTextContent (_resp, "Unknown user id given");
+				WebUtils.WriteText (_context.Response, "Unknown user id given", HttpStatusCode.NotFound);
 				return;
 			}
 
-			GetInventoryArguments (_req, out bool showIconColor, out bool showIconName);
+			GetInventoryArguments (_context.Request, out bool showIconColor, out bool showIconName);
 
 			JSONObject result = DoPlayer (userIdString, p, showIconColor, showIconName);
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 
Index: binary-improvements2/MapRendering/Web/API/GetPlayerList.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetPlayerList.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetPlayerList.cs	(revision 387)
@@ -5,9 +5,7 @@
 using AllocsFixes.JSON;
 using AllocsFixes.PersistentData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetPlayerList : WebAPI {
+	public class GetPlayerList : AbsWebAPI {
 		private static readonly Regex numberFilterMatcher =
 			new Regex (@"^(>=|=>|>|<=|=<|<|==|=)?\s*([0-9]+(\.[0-9]*)?)$");
@@ -17,21 +15,20 @@
 #endif
 
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+		public override void HandleRequest (RequestContext _context) {
 			AdminTools admTools = GameManager.Instance.adminTools;
-			PlatformUserIdentifierAbs userId = _user?.UserId;
-
-			bool bViewAll = WebConnection.CanViewAllPlayers (_permissionLevel);
+			PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
+
+			bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel);
 
 			// TODO: Sort (and filter?) prior to converting to JSON ... hard as how to get the correct column's data? (i.e. column name matches JSON object field names, not source data)
 
 			int rowsPerPage = 25;
-			if (_req.QueryString ["rowsperpage"] != null) {
-				int.TryParse (_req.QueryString ["rowsperpage"], out rowsPerPage);
+			if (_context.Request.QueryString ["rowsperpage"] != null) {
+				int.TryParse (_context.Request.QueryString ["rowsperpage"], out rowsPerPage);
 			}
 
 			int page = 0;
-			if (_req.QueryString ["page"] != null) {
-				int.TryParse (_req.QueryString ["page"], out page);
+			if (_context.Request.QueryString ["page"] != null) {
+				int.TryParse (_context.Request.QueryString ["page"], out page);
 			}
 
@@ -83,9 +80,9 @@
 			IEnumerable<JSONObject> list = playerList;
 
-			foreach (string key in _req.QueryString.AllKeys) {
+			foreach (string key in _context.Request.QueryString.AllKeys) {
 				if (!string.IsNullOrEmpty (key) && key.StartsWith ("filter[")) {
 					string filterCol = key.Substring (key.IndexOf ('[') + 1);
 					filterCol = filterCol.Substring (0, filterCol.Length - 1);
-					string filterVal = _req.QueryString.Get (key).Trim ();
+					string filterVal = _context.Request.QueryString.Get (key).Trim ();
 
 					list = ExecuteFilter (list, filterCol, filterVal);
@@ -95,9 +92,9 @@
 			int totalAfterFilter = list.Count ();
 
-			foreach (string key in _req.QueryString.AllKeys) {
+			foreach (string key in _context.Request.QueryString.AllKeys) {
 				if (!string.IsNullOrEmpty (key) && key.StartsWith ("sort[")) {
 					string sortCol = key.Substring (key.IndexOf ('[') + 1);
 					sortCol = sortCol.Substring (0, sortCol.Length - 1);
-					string sortVal = _req.QueryString.Get (key);
+					string sortVal = _context.Request.QueryString.Get (key);
 
 					list = ExecuteSort (list, sortCol, sortVal == "0");
@@ -120,5 +117,5 @@
 			result.Add ("players", playersJsResult);
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 
Index: binary-improvements2/MapRendering/Web/API/GetPlayersLocation.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetPlayersLocation.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetPlayersLocation.cs	(revision 387)
@@ -2,20 +2,17 @@
 using AllocsFixes.JSON;
 using AllocsFixes.PersistentData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetPlayersLocation : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetPlayersLocation : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			AdminTools admTools = GameManager.Instance.adminTools;
-			PlatformUserIdentifierAbs userId = _user?.UserId;
+			PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
 
 			bool listOffline = false;
-			if (_req.QueryString ["offline"] != null) {
-				bool.TryParse (_req.QueryString ["offline"], out listOffline);
+			if (_context.Request.QueryString ["offline"] != null) {
+				bool.TryParse (_context.Request.QueryString ["offline"], out listOffline);
 			}
 
-			bool bViewAll = WebConnection.CanViewAllPlayers (_permissionLevel);
+			bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel);
 
 			JSONArray playersJsResult = new JSONArray ();
@@ -57,5 +54,5 @@
 			}
 
-			WriteJSON (_resp, playersJsResult);
+			WebUtils.WriteJson (_context.Response, playersJsResult);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetPlayersOnline.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetPlayersOnline.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetPlayersOnline.cs	(revision 387)
@@ -2,11 +2,8 @@
 using AllocsFixes.JSON;
 using AllocsFixes.PersistentData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetPlayersOnline : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetPlayersOnline : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			JSONArray players = new JSONArray ();
 
@@ -44,5 +41,5 @@
 			}
 
-			WriteJSON (_resp, players);
+			WebUtils.WriteJson (_context.Response, players);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetServerInfo.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetServerInfo.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetServerInfo.cs	(revision 387)
@@ -1,11 +1,8 @@
 using System;
 using AllocsFixes.JSON;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetServerInfo : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetServerInfo : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			JSONObject serverInfo = new JSONObject ();
 
@@ -43,5 +40,5 @@
 
 
-			WriteJSON (_resp, serverInfo);
+			WebUtils.WriteJson (_context.Response, serverInfo);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/GetStats.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetStats.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetStats.cs	(revision 387)
@@ -1,11 +1,8 @@
 using AllocsFixes.JSON;
 using AllocsFixes.LiveData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetStats : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetStats : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			JSONObject result = new JSONObject ();
 
@@ -20,5 +17,5 @@
 			result.Add ("animals", new JSONNumber (Animals.Instance.GetCount ()));
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 
Index: binary-improvements2/MapRendering/Web/API/GetWebMods.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetWebMods.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetWebMods.cs	(revision 387)
@@ -1,8 +1,6 @@
 using AllocsFixes.JSON;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetWebMods : WebAPI {
+	public class GetWebMods : AbsWebAPI {
 		private readonly JSONArray loadedWebMods = new JSONArray ();
 
@@ -27,8 +25,6 @@
 		}
 
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
-
-			WriteJSON (_resp, loadedWebMods);
+		public override void HandleRequest (RequestContext _context) {
+			WebUtils.WriteJson (_context.Response, loadedWebMods);
 		}
 
Index: binary-improvements2/MapRendering/Web/API/GetWebUIUpdates.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetWebUIUpdates.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetWebUIUpdates.cs	(revision 387)
@@ -1,14 +1,11 @@
 using AllocsFixes.JSON;
 using AllocsFixes.LiveData;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class GetWebUIUpdates : WebAPI {
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
+	public class GetWebUIUpdates : AbsWebAPI {
+		public override void HandleRequest (RequestContext _context) {
 			int latestLine;
-			if (_req.QueryString ["latestLine"] == null ||
-			    !int.TryParse (_req.QueryString ["latestLine"], out latestLine)) {
+			if (_context.Request.QueryString ["latestLine"] == null ||
+			    !int.TryParse (_context.Request.QueryString ["latestLine"], out latestLine)) {
 				latestLine = 0;
 			}
@@ -28,5 +25,5 @@
 			result.Add ("newlogs", new JSONNumber (LogBuffer.Instance.LatestLine - latestLine));
 
-			WriteJSON (_resp, result);
+			WebUtils.WriteJson (_context.Response, result);
 		}
 
Index: binary-improvements2/MapRendering/Web/API/Null.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/Null.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/Null.cs	(revision 387)
@@ -1,17 +1,14 @@
 ﻿using System.Text;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public class Null : WebAPI {
+	public class Null : AbsWebAPI {
 		public Null (string _name) : base(_name) {
 		}
 		
-		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
-			int _permissionLevel) {
-			_resp.ContentLength64 = 0;
-			_resp.ContentType = "text/plain";
-			_resp.ContentEncoding = Encoding.ASCII;
-			_resp.OutputStream.Write (new byte[] { }, 0, 0);
+		public override void HandleRequest (RequestContext _context) {
+			_context.Response.ContentLength64 = 0;
+			_context.Response.ContentType = "text/plain";
+			_context.Response.ContentEncoding = Encoding.ASCII;
+			_context.Response.OutputStream.Write (new byte[] { }, 0, 0);
 		}
 	}
Index: binary-improvements2/MapRendering/Web/API/WebAPI.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/WebAPI.cs	(revision 384)
+++ 	(revision )
@@ -1,54 +1,0 @@
-using System.Text;
-using AllocsFixes.JSON;
-using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
-
-namespace AllocsFixes.NetConnections.Servers.Web.API {
-	public abstract class WebAPI {
-		public readonly string Name;
-
-		protected WebAPI (string _name = null) {
-			Name = _name ?? GetType ().Name;
-		}
-
-#if ENABLE_PROFILER
-		private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Serialize");
-		private static readonly UnityEngine.Profiling.CustomSampler netWriteSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Write");
-#endif
-
-		public static void WriteJSON (HttpListenerResponse _resp, JSONNode _root) {
-#if ENABLE_PROFILER
-			jsonSerializeSampler.Begin ();
-#endif
-			StringBuilder sb = new StringBuilder ();
-			_root.ToString (sb);
-#if ENABLE_PROFILER
-			jsonSerializeSampler.End ();
-			netWriteSampler.Begin ();
-#endif
-			byte[] buf = Encoding.UTF8.GetBytes (sb.ToString ());
-			_resp.ContentLength64 = buf.Length;
-			_resp.ContentType = "application/json";
-			_resp.ContentEncoding = Encoding.UTF8;
-			_resp.OutputStream.Write (buf, 0, buf.Length);
-#if ENABLE_PROFILER
-			netWriteSampler.End ();
-#endif
-		}
-
-		public static void WriteText (HttpListenerResponse _resp, string _text) {
-			byte[] buf = Encoding.UTF8.GetBytes (_text);
-			_resp.ContentLength64 = buf.Length;
-			_resp.ContentType = "text/plain";
-			_resp.ContentEncoding = Encoding.UTF8;
-			_resp.OutputStream.Write (buf, 0, buf.Length);
-		}
-
-		public abstract void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp,
-			WebConnection _user, int _permissionLevel);
-
-		public virtual int DefaultPermissionLevel () {
-			return 0;
-		}
-	}
-}
