Index: binary-improvements/MapRendering/Web/Web.cs
===================================================================
--- binary-improvements/MapRendering/Web/Web.cs	(revision 360)
+++ binary-improvements/MapRendering/Web/Web.cs	(revision 367)
@@ -9,6 +9,6 @@
 using AllocsFixes.FileCache;
 using AllocsFixes.NetConnections.Servers.Web.Handlers;
+using AllocsFixes.NetConnections.Servers.Web.SSE;
 using UnityEngine;
-using UnityEngine.Profiling;
 
 namespace AllocsFixes.NetConnections.Servers.Web {
@@ -18,10 +18,8 @@
 		public static int currentHandlers;
 		public static long totalHandlingTime = 0;
-		private readonly HttpListener _listener = new HttpListener ();
-		private readonly string dataFolder;
+		private readonly HttpListener listener = new HttpListener ();
 		private readonly Dictionary<string, PathHandler> handlers = new CaseInsensitiveStringDictionary<PathHandler> ();
-		private readonly bool useStaticCache;
-
-		public ConnectionHandler connectionHandler;
+
+		public readonly ConnectionHandler connectionHandler;
 
 		public Web () {
@@ -40,7 +38,7 @@
 
 				// TODO: Read from config
-				useStaticCache = false;
-
-				dataFolder = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver";
+				bool useStaticCache = false;
+
+				string dataFolder = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver";
 
 				if (!HttpListener.IsSupported) {
@@ -49,52 +47,16 @@
 				}
 
-				handlers.Add (
-					"/index.htm",
-					new SimpleRedirectHandler ("/static/index.html"));
-				handlers.Add (
-					"/favicon.ico",
-					new SimpleRedirectHandler ("/static/favicon.ico"));
-				handlers.Add (
-					"/session/",
-					new SessionHandler (
-						"/session/",
+				
+				RegisterPathHandler ("/index.htm", new SimpleRedirectHandler ("/static/index.html"));
+				RegisterPathHandler ("/favicon.ico", new SimpleRedirectHandler ("/static/favicon.ico"));
+				RegisterPathHandler ("/session/", new SessionHandler (dataFolder));
+				RegisterPathHandler ("/userstatus", new UserStatusHandler ());
+				RegisterPathHandler ("/static/", new StaticHandler (
 						dataFolder,
-						this)
+						useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (),
+						false)
 				);
-				handlers.Add (
-					"/userstatus",
-					new UserStatusHandler ()
-				);
-				if (useStaticCache) {
-					handlers.Add (
-						"/static/",
-						new StaticHandler (
-							"/static/",
-							dataFolder,
-							new SimpleCache (),
-							false)
-					);
-				} else {
-					handlers.Add (
-						"/static/",
-						new StaticHandler (
-							"/static/",
-							dataFolder,
-							new DirectAccess (),
-							false)
-					);
-				}
-
-				handlers.Add (
-					"/itemicons/",
-					new ItemIconHandler (
-						"/itemicons/",
-						true)
-				);
-
-				handlers.Add (
-					"/map/",
-					new StaticHandler (
-						"/map/",
+				RegisterPathHandler ("/itemicons/", new ItemIconHandler (true));
+				RegisterPathHandler ("/map/", new StaticHandler (
 						GameUtils.GetSaveGameDir () + "/map",
 						MapRendering.MapRendering.GetTileCache (),
@@ -102,18 +64,15 @@
 						"web.map")
 				);
-
-				handlers.Add (
-					"/api/",
-					new ApiHandler ("/api/")
-				);
+				RegisterPathHandler ("/api/", new ApiHandler ());
+				RegisterPathHandler ("/sse/", new SseHandler ());
 
 				connectionHandler = new ConnectionHandler ();
 
-				_listener.Prefixes.Add (string.Format ("http://*:{0}/", webPort + 2));
-				_listener.Start ();
+				listener.Prefixes.Add ($"http://*:{webPort + 2}/");
+				listener.Start ();
 
 				SdtdConsole.Instance.RegisterServer (this);
 
-				_listener.BeginGetContext (HandleRequest, _listener);
+				listener.BeginGetContext (HandleRequest, listener);
 
 				Log.Out ("Started Webserver on " + (webPort + 2));
@@ -123,8 +82,18 @@
 		}
 
+		public void RegisterPathHandler (string _urlBasePath, PathHandler _handler) {
+			if (handlers.ContainsKey (_urlBasePath)) {
+				Log.Error ($"Web: Handler for relative path {_urlBasePath} already registerd.");
+				return;
+			}
+			
+			handlers.Add (_urlBasePath, _handler);
+			_handler.SetBasePathAndParent (this, _urlBasePath);
+		}
+
 		public void Disconnect () {
 			try {
-				_listener.Stop ();
-				_listener.Close ();
+				listener.Stop ();
+				listener.Close ();
 			} catch (Exception e) {
 				Log.Out ("Error in Web.Disconnect: " + e);
@@ -132,4 +101,10 @@
 		}
 
+		public void Shutdown () {
+			foreach (KeyValuePair<string, PathHandler> kvp in handlers) {
+				kvp.Value.Shutdown ();
+			}
+		}
+
 		public void SendLine (string _line) {
 			connectionHandler.SendLine (_line);
@@ -140,11 +115,7 @@
 		}
 
-		public static bool isSslRedirected (HttpListenerRequest _req) {
+		public static bool IsSslRedirected (HttpListenerRequest _req) {
 			string proto = _req.Headers ["X-Forwarded-Proto"];
-			if (!string.IsNullOrEmpty (proto)) {
-				return proto.Equals ("https", StringComparison.OrdinalIgnoreCase);
-			}
-
-			return false;
+			return !string.IsNullOrEmpty (proto) && proto.Equals ("https", StringComparison.OrdinalIgnoreCase);
 		}
 		
@@ -152,10 +123,10 @@
 		
 #if ENABLE_PROFILER
-		private readonly CustomSampler authSampler = CustomSampler.Create ("Auth");
-		private readonly CustomSampler handlerSampler = CustomSampler.Create ("Handler");
+		private readonly UnityEngine.Profiling.CustomSampler authSampler = UnityEngine.Profiling.CustomSampler.Create ("Auth");
+		private readonly UnityEngine.Profiling.CustomSampler handlerSampler = UnityEngine.Profiling.CustomSampler.Create ("Handler");
 #endif
 
 		private void HandleRequest (IAsyncResult _result) {
-			if (!_listener.IsListening) {
+			if (!listener.IsListening) {
 				return;
 			}
@@ -166,10 +137,10 @@
 //				MicroStopwatch msw = new MicroStopwatch ();
 #if ENABLE_PROFILER
-			Profiler.BeginThreadProfiling ("AllocsMods", "WebRequest");
+			UnityEngine.Profiling.Profiler.BeginThreadProfiling ("AllocsMods", "WebRequest");
 			HttpListenerContext ctx = _listener.EndGetContext (_result);
 			try {
 #else
-			HttpListenerContext ctx = _listener.EndGetContext (_result);
-			_listener.BeginGetContext (HandleRequest, _listener);
+			HttpListenerContext ctx = listener.EndGetContext (_result);
+			listener.BeginGetContext (HandleRequest, listener);
 #endif
 			try {
@@ -180,9 +151,8 @@
 				response.ProtocolVersion = HttpProtocolVersion;
 
-				WebConnection conn;
 #if ENABLE_PROFILER
 				authSampler.Begin ();
 #endif
-				int permissionLevel = DoAuthentication (request, out conn);
+				int permissionLevel = DoAuthentication (request, out WebConnection conn);
 #if ENABLE_PROFILER
 				authSampler.End ();
@@ -194,9 +164,10 @@
 
 				if (conn != null) {
-					Cookie cookie = new Cookie ("sid", conn.SessionID, "/");
-					cookie.Expired = false;
-					cookie.Expires = new DateTime (2020, 1, 1);
-					cookie.HttpOnly = true;
-					cookie.Secure = false;
+					Cookie cookie = new Cookie ("sid", conn.SessionID, "/") {
+						Expired = false,
+						Expires = DateTime.MinValue,
+						HttpOnly = true,
+						Secure = false
+					};
 					response.AppendCookie (cookie);
 				}
@@ -260,5 +231,5 @@
 			} finally {
 				_listener.BeginGetContext (HandleRequest, _listener);
-				Profiler.EndThreadProfiling ();
+				UnityEngine.Profiling.Profiler.EndThreadProfiling ();
 			}
 #endif
@@ -281,4 +252,6 @@
 			}
 
+			string remoteEndpointString = _req.RemoteEndPoint.ToString ();
+
 			if (_req.QueryString ["adminuser"] != null && _req.QueryString ["admintoken"] != null) {
 				WebPermissions.AdminToken admin = WebPermissions.Instance.GetWebAdmin (_req.QueryString ["adminuser"],
@@ -288,5 +261,5 @@
 				}
 
-				Log.Warning ("Invalid Admintoken used from " + _req.RemoteEndPoint);
+				Log.Warning ("Invalid Admintoken used from " + remoteEndpointString);
 			}
 
@@ -299,9 +272,9 @@
 						int level = GameManager.Instance.adminTools.GetUserPermissionLevel (id.ToString ());
 						Log.Out ("Steam OpenID login from {0} with ID {1}, permission level {2}",
-							_req.RemoteEndPoint.ToString (), con.SteamID, level);
+							remoteEndpointString, con.SteamID, level);
 						return level;
 					}
 
-					Log.Out ("Steam OpenID login failed from {0}", _req.RemoteEndPoint.ToString ());
+					Log.Out ("Steam OpenID login failed from {0}", remoteEndpointString);
 				} catch (Exception e) {
 					Log.Error ("Error validating login:");
