Index: binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs
===================================================================
--- binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs	(revision 391)
+++ binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs	(revision 394)
@@ -48,7 +48,5 @@
 		}
 
-#if ENABLE_PROFILER
 		private static readonly UnityEngine.Profiling.CustomSampler apiHandlerSampler = UnityEngine.Profiling.CustomSampler.Create ("API_Handler");
-#endif
 
 		public override void HandleRequest (RequestContext _context) {
@@ -83,11 +81,7 @@
 
 			try {
-#if ENABLE_PROFILER
 				apiHandlerSampler.Begin ();
-#endif
 				api.HandleRequest (_context);
-#if ENABLE_PROFILER
 				apiHandlerSampler.End ();
-#endif
 			} catch (Exception e) {
 				Log.Error ($"Error in {nameof(ApiHandler)}.HandleRequest(): Handler {api.Name} threw an exception:");
Index: binary-improvements2/WebServer/src/UrlHandlers/SessionHandler.cs
===================================================================
--- binary-improvements2/WebServer/src/UrlHandlers/SessionHandler.cs	(revision 391)
+++ binary-improvements2/WebServer/src/UrlHandlers/SessionHandler.cs	(revision 394)
@@ -1,35 +1,21 @@
 using System;
-using System.IO;
 using System.Net;
-using System.Text;
 
 namespace Webserver.UrlHandlers {
 	public class SessionHandler : AbsHandler {
-		private const string pageBasePath = "/";
+		private const string pageBasePath = "/app";
+		private const string pageErrorPath = "/app/error/";
 		private const string steamOpenIdVerifyUrl = "verifysteamopenid";
 		private const string steamLoginUrl = "loginsteam";
-		
-		private readonly string footer = "";
-		private readonly string header = "";
 
 		private readonly ConnectionHandler connectionHandler;
 
-		public SessionHandler (string _dataFolder, ConnectionHandler _connectionHandler) : base (null) {
+		public SessionHandler (ConnectionHandler _connectionHandler) : base (null) {
 			connectionHandler = _connectionHandler;
-			
-			if (File.Exists (_dataFolder + "/sessionheader.tmpl")) {
-				header = File.ReadAllText (_dataFolder + "/sessionheader.tmpl");
-			}
-
-			if (File.Exists (_dataFolder + "/sessionfooter.tmpl")) {
-				footer = File.ReadAllText (_dataFolder + "/sessionfooter.tmpl");
-			}
 		}
 
 		public override void HandleRequest (RequestContext _context) {
-			
-			IPEndPoint reqRemoteEndPoint = _context.Request.RemoteEndPoint;
-			if (reqRemoteEndPoint == null) {
-				_context.Response.Redirect (pageBasePath);
+			if (_context.Request.RemoteEndPoint == null) {
+				_context.Response.Redirect (pageErrorPath + "NoRemoteEndpoint");
 				return;
 			}
@@ -37,61 +23,74 @@
 			string subpath = _context.RequestPath.Remove (0, urlBasePath.Length);
 
-			StringBuilder result = new StringBuilder ();
-			result.Append (header);
+			if (subpath.StartsWith (steamOpenIdVerifyUrl)) {
+				HandleSteamVerification (_context);
+				return;
+			}
 
-			if (subpath.StartsWith (steamOpenIdVerifyUrl)) {
-				string remoteEndpointString = reqRemoteEndPoint.ToString ();
+			if (subpath.StartsWith ("logout")) {
+				HandleLogout (_context);
+				return;
+			}
 
-				try {
-					ulong id = OpenID.Validate (_context.Request);
-					if (id > 0) {
-						WebConnection con = connectionHandler.LogIn (id, reqRemoteEndPoint.Address);
-						int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId);
-						Log.Out ("Steam OpenID login from {0} with ID {1}, permission level {2}",
-							remoteEndpointString, con.UserId, level);
-						
-						Cookie cookie = new Cookie ("sid", con.SessionID, "/") {
-							Expired = false,
-							Expires = DateTime.MinValue,
-							HttpOnly = true,
-							Secure = false
-						};
-						_context.Response.AppendCookie (cookie);
-						_context.Response.Redirect (pageBasePath);
+			if (subpath.StartsWith (steamLoginUrl)) {
+				HandleSteamLogin (_context);
+				return;
+			}
 
-						return;
-					}
-				} catch (Exception e) {
-					Log.Error ("Error validating login:");
-					Log.Exception (e);
-				}
+			_context.Response.Redirect (pageErrorPath + "InvalidSessionsCommand");
+		}
 
-				Log.Out ($"Steam OpenID login failed from {remoteEndpointString}");
-				result.Append ($"<h1>Login failed, <a href=\"{pageBasePath}\">click to return to main page</a>.</h1>");
-			} else if (subpath.StartsWith ("logout")) {
-				if (_context.Connection != null) {
-					connectionHandler.LogOut (_context.Connection.SessionID);
-					Cookie cookie = new Cookie ("sid", "", "/") {
-						Expired = true
+		private void HandleSteamLogin (RequestContext _context) {
+			string host = (WebUtils.IsSslRedirected (_context.Request) ? "https://" : "http://") + _context.Request.UserHostName;
+			string url = OpenID.GetOpenIdLoginUrl (host, host + urlBasePath + steamOpenIdVerifyUrl);
+			_context.Response.Redirect (url);
+		}
+
+		private void HandleLogout (RequestContext _context) {
+			Cookie cookie = new Cookie ("sid", "", "/") {
+				Expired = true
+			};
+			_context.Response.AppendCookie (cookie);
+
+			if (_context.Connection == null) {
+				_context.Response.Redirect (pageErrorPath + "NotLoggedIn");
+				return;
+			}
+
+			connectionHandler.LogOut (_context.Connection.SessionID);
+			_context.Response.Redirect (pageBasePath);
+		}
+
+		private void HandleSteamVerification (RequestContext _context) {
+			string remoteEndpointString = _context.Request.RemoteEndPoint!.ToString ();
+
+			try {
+				ulong id = OpenID.Validate (_context.Request);
+				if (id > 0) {
+					WebConnection con = connectionHandler.LogIn (id, _context.Request.RemoteEndPoint.Address);
+					int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId);
+					Log.Out ("Steam OpenID login from {0} with ID {1}, permission level {2}",
+						remoteEndpointString, con.UserId, level);
+
+					Cookie cookie = new Cookie ("sid", con.SessionID, "/") {
+						Expired = false,
+						Expires = DateTime.MinValue,
+						HttpOnly = true,
+						Secure = false
 					};
 					_context.Response.AppendCookie (cookie);
 					_context.Response.Redirect (pageBasePath);
+
 					return;
 				}
-
-				result.Append ($"<h1>Not logged in, <a href=\"{pageBasePath}\">click to return to main page</a>.</h1>");
-			} else if (subpath.StartsWith (steamLoginUrl)) {
-				string host = (WebUtils.IsSslRedirected (_context.Request) ? "https://" : "http://") + _context.Request.UserHostName;
-				string url = OpenID.GetOpenIdLoginUrl (host, host + urlBasePath + steamOpenIdVerifyUrl);
-				_context.Response.Redirect (url);
-				return;
-			} else {
-				result.Append ($"<h1>Unknown command, <a href=\"{pageBasePath}\">click to return to main page</a>.</h1>");
+			} catch (Exception e) {
+				Log.Error ("Error validating login:");
+				Log.Exception (e);
 			}
 
-			result.Append (footer);
+			Log.Out ($"Steam OpenID login failed from {remoteEndpointString}");
+			_context.Response.Redirect (pageErrorPath + "SteamLoginFailed");
+		}
 
-			WebUtils.WriteText (_context.Response, result.ToString (), _mimeType: WebUtils.MimeHtml);
-		}
 	}
 }
Index: binary-improvements2/WebServer/src/Web.cs
===================================================================
--- binary-improvements2/WebServer/src/Web.cs	(revision 391)
+++ binary-improvements2/WebServer/src/Web.cs	(revision 394)
@@ -63,5 +63,5 @@
 				RegisterWebMods (useStaticCache);
 
-				RegisterPathHandler ("/session/", new SessionHandler (webfilesFolder, connectionHandler));
+				RegisterPathHandler ("/session/", new SessionHandler (connectionHandler));
 				RegisterPathHandler ("/userstatus", new UserStatusHandler ());
 				RegisterPathHandler ("/sse/", new SseHandler ());
@@ -152,8 +152,8 @@
 		}
 
-#if ENABLE_PROFILER
+		private readonly UnityEngine.Profiling.CustomSampler getContextSampler = UnityEngine.Profiling.CustomSampler.Create ("GetCtx");
 		private readonly UnityEngine.Profiling.CustomSampler authSampler = UnityEngine.Profiling.CustomSampler.Create ("Auth");
+		private readonly UnityEngine.Profiling.CustomSampler cookieSampler = UnityEngine.Profiling.CustomSampler.Create ("ConCookie");
 		private readonly UnityEngine.Profiling.CustomSampler handlerSampler = UnityEngine.Profiling.CustomSampler.Create ("Handler");
-#endif
 
 		private void HandleRequest (IAsyncResult _result) {
@@ -165,5 +165,7 @@
 #if ENABLE_PROFILER
 			UnityEngine.Profiling.Profiler.BeginThreadProfiling ("AllocsMods", "WebRequest");
+			getContextSampler.Begin ();
 			HttpListenerContext ctx = listenerInstance.EndGetContext (_result);
+			getContextSampler.End ();
 			try {
 #else
@@ -189,14 +191,11 @@
 				}
 
-#if ENABLE_PROFILER
 				authSampler.Begin ();
-#endif
 				int permissionLevel = DoAuthentication (request, out WebConnection conn);
-#if ENABLE_PROFILER
 				authSampler.End ();
-#endif
 
 				//Log.Out ("Login status: conn!=null: {0}, permissionlevel: {1}", conn != null, permissionLevel);
 
+				cookieSampler.Begin ();
 				if (conn != null) {
 					Cookie cookie = new Cookie ("sid", conn.SessionID, "/") {
@@ -208,4 +207,5 @@
 					response.AppendCookie (cookie);
 				}
+				cookieSampler.End ();
 
 				string requestPath = request.Url.AbsolutePath;
@@ -256,11 +256,7 @@
 					}
 				} else {
-#if ENABLE_PROFILER
 					handlerSampler.Begin ();
-#endif
 					handler.HandleRequest (_context);
-#if ENABLE_PROFILER
 					handlerSampler.End ();
-#endif
 				}
 
@@ -291,6 +287,4 @@
 			}
 
-			string remoteEndpointString = reqRemoteEndPoint.ToString ();
-
 			if (_req.QueryString ["adminuser"] == null || _req.QueryString ["admintoken"] == null) {
 				return guestPermissionLevel;
@@ -303,5 +297,5 @@
 			}
 
-			Log.Warning ("Invalid Admintoken used from " + remoteEndpointString);
+			Log.Warning ("Invalid Admintoken used from " + reqRemoteEndPoint);
 
 			return guestPermissionLevel;
Index: binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 391)
+++ binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 394)
@@ -6,4 +6,6 @@
 namespace Webserver.WebAPI {
 	public abstract class AbsRestApi : AbsWebAPI {
+		private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize");
+
 		public sealed override void HandleRequest (RequestContext _context) {
 			JsonNode jsonBody = null;
@@ -14,6 +16,10 @@
 				if (!string.IsNullOrEmpty (body)) {
 					try {
+						jsonDeserializeSampler.Begin ();
 						jsonBody = Parser.Parse (body);
+						jsonDeserializeSampler.End ();
 					} catch (Exception e) {
+						jsonDeserializeSampler.End ();
+
 						SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
 						return;
Index: binary-improvements2/WebServer/src/WebAPI/GetPlayerList.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/GetPlayerList.cs	(revision 391)
+++ binary-improvements2/WebServer/src/WebAPI/GetPlayerList.cs	(revision 394)
@@ -13,7 +13,5 @@
 			new Regex (@"^(>=|=>|>|<=|=<|<|==|=)?\s*([0-9]+(\.[0-9]*)?)$");
 
-#if ENABLE_PROFILER
 		private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Build");
-#endif
 
 		public override void HandleRequest (RequestContext _context) {
@@ -42,7 +40,5 @@
 			List<JsonObject> playerList = new List<JsonObject> ();
 
-#if ENABLE_PROFILER
 			jsonSerializeSampler.Begin ();
-#endif
 
 			foreach (KeyValuePair<PlatformUserIdentifierAbs, Player> kvp in playersList.Dict) {
@@ -76,7 +72,5 @@
 			}
 
-#if ENABLE_PROFILER
 			jsonSerializeSampler.End ();
-#endif
 
 			IEnumerable<JsonObject> list = playerList;
Index: binary-improvements2/WebServer/src/WebUtils.cs
===================================================================
--- binary-improvements2/WebServer/src/WebUtils.cs	(revision 391)
+++ binary-improvements2/WebServer/src/WebUtils.cs	(revision 394)
@@ -12,23 +12,15 @@
 		public const string MimeJson = "application/json";
 		
-#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, HttpStatusCode _statusCode = HttpStatusCode.OK) {
-#if ENABLE_PROFILER
 			jsonSerializeSampler.Begin ();
-#endif
 			StringBuilder sb = new StringBuilder ();
 			_root.ToString (sb);
-#if ENABLE_PROFILER
 			jsonSerializeSampler.End ();
 			netWriteSampler.Begin ();
-#endif
 			WriteText (_resp, sb.ToString(), _statusCode, MimeJson);
-#if ENABLE_PROFILER
 			netWriteSampler.End ();
-#endif
 		}
 
