Changeset 382 for binary-improvements2/MapRendering/Web/Web.cs
- Timestamp:
- Aug 1, 2022, 12:54:31 PM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
binary-improvements2/MapRendering/Web/Web.cs
r369 r382 2 2 using System.Collections.Generic; 3 3 using System.IO; 4 using System.Net;5 4 using System.Net.Sockets; 6 using System.Reflection; 5 using Cookie = System.Net.Cookie; 6 using HttpStatusCode = System.Net.HttpStatusCode; 7 using IPEndPoint = System.Net.IPEndPoint; 7 8 using System.Text; 8 9 using System.Threading; … … 10 11 using AllocsFixes.NetConnections.Servers.Web.Handlers; 11 12 using AllocsFixes.NetConnections.Servers.Web.SSE; 13 using SpaceWizards.HttpListener; 12 14 using UnityEngine; 13 15 14 16 namespace AllocsFixes.NetConnections.Servers.Web { 15 17 public class Web : IConsoleServer { 16 private const int GUEST_PERMISSION_LEVEL = 2000; 18 private const int guestPermissionLevel = 2000; 19 private const string indexPagePath = "/app"; 20 17 21 public static int handlingCount; 18 22 public static int currentHandlers; 19 23 public static long totalHandlingTime = 0; 24 private readonly List<AbsHandler> handlers = new List<AbsHandler> (); 25 private readonly ConnectionHandler connectionHandler; 26 20 27 private readonly HttpListener listener = new HttpListener (); 21 private readonly Dictionary<string, PathHandler> handlers = new CaseInsensitiveStringDictionary<PathHandler> (); 22 23 public readonly ConnectionHandler connectionHandler; 24 25 public Web () { 28 private readonly Version httpProtocolVersion = new Version(1, 1); 29 30 public Web (string _modInstancePath) { 26 31 try { 27 32 int webPort = GamePrefs.GetInt (EnumUtils.Parse<EnumGamePrefs> ("ControlPanelPort")); … … 31 36 } 32 37 33 if (!Directory.Exists (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + 34 "/webserver")) { 35 Log.Out ("Webserver not started (folder \"webserver\" not found in WebInterface mod folder)"); 38 // TODO: Remove once this becomes the default control panel 39 webPort += 2; 40 41 if (!HttpListener.IsSupported) { 42 Log.Out ("Webserver not started (needs Windows XP SP2, Server 2003 or later or Mono)"); 36 43 return; 37 44 } … … 40 47 bool useStaticCache = false; 41 48 42 string dataFolder = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver"; 43 44 if (!HttpListener.IsSupported) { 45 Log.Out ("Webserver not started (needs Windows XP SP2, Server 2003 or later or Mono)"); 46 return; 47 } 48 49 50 RegisterPathHandler ("/index.htm", new SimpleRedirectHandler ("/static/index.html")); 51 RegisterPathHandler ("/favicon.ico", new SimpleRedirectHandler ("/static/favicon.ico")); 52 RegisterPathHandler ("/session/", new SessionHandler (dataFolder)); 49 string webfilesFolder = _modInstancePath + "/webserver"; 50 string webfilesFolderLegacy = _modInstancePath + "/weblegacy"; 51 52 connectionHandler = new ConnectionHandler (); 53 54 RegisterPathHandler ("/", new RewriteHandler ("/files/")); 55 56 // React virtual routing 57 RegisterPathHandler ("/app", new RewriteHandler ("/files/index.html", true)); 58 59 // Legacy web page 60 RegisterPathHandler ("/weblegacy", new StaticHandler ( 61 webfilesFolderLegacy, 62 useStaticCache ? (AbstractCache)new SimpleCache () : new DirectAccess (), 63 false) 64 ); 65 66 RegisterPathHandler ("/session/", new SessionHandler (webfilesFolder, connectionHandler)); 53 67 RegisterPathHandler ("/userstatus", new UserStatusHandler ()); 54 RegisterPathHandler ("/ static/", new StaticHandler (55 dataFolder,68 RegisterPathHandler ("/files/", new StaticHandler ( 69 webfilesFolder, 56 70 useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (), 57 71 false) … … 67 81 RegisterPathHandler ("/sse/", new SseHandler ()); 68 82 69 connectionHandler = new ConnectionHandler (); 70 71 listener.Prefixes.Add ($"http://*:{webPort + 2}/"); 83 listener.Prefixes.Add ($"http://+:{webPort}/"); 84 // listener.Prefixes.Add ($"http://[::1]:{webPort}/"); 72 85 listener.Start (); 86 listener.BeginGetContext (HandleRequest, listener); 73 87 74 88 SdtdConsole.Instance.RegisterServer (this); 75 89 76 listener.BeginGetContext (HandleRequest, listener); 77 78 Log.Out ("Started Webserver on " + (webPort + 2)); 90 Log.Out ("Started Webserver on " + webPort); 79 91 } catch (Exception e) { 80 Log.Out ("Error in Web.ctor: " + e); 81 } 82 } 83 84 public void RegisterPathHandler (string _urlBasePath, PathHandler _handler) { 85 if (handlers.ContainsKey (_urlBasePath)) { 86 Log.Error ($"Web: Handler for relative path {_urlBasePath} already registerd."); 87 return; 92 Log.Error ("Error in Web.ctor: "); 93 Log.Exception (e); 94 } 95 } 96 97 public void RegisterPathHandler (string _urlBasePath, AbsHandler _handler) { 98 foreach (AbsHandler handler in handlers) { 99 if (handler.UrlBasePath == _urlBasePath) { 100 Log.Error ($"Web: Handler for relative path {_urlBasePath} already registerd."); 101 return; 102 } 88 103 } 89 104 90 handlers.Add (_ urlBasePath, _handler);105 handlers.Add (_handler); 91 106 _handler.SetBasePathAndParent (this, _urlBasePath); 92 107 } … … 102 117 103 118 public void Shutdown () { 104 foreach ( KeyValuePair<string, PathHandler> kvpin handlers) {105 kvp.Value.Shutdown ();119 foreach (AbsHandler handler in handlers) { 120 handler.Shutdown (); 106 121 } 107 122 } … … 120 135 } 121 136 122 private readonly Version HttpProtocolVersion = new Version(1, 1);123 124 137 #if ENABLE_PROFILER 125 138 private readonly UnityEngine.Profiling.CustomSampler authSampler = UnityEngine.Profiling.CustomSampler.Create ("Auth"); … … 128 141 129 142 private void HandleRequest (IAsyncResult _result) { 130 if (!listener.IsListening) { 143 HttpListener listenerInstance = (HttpListener)_result.AsyncState; 144 if (!listenerInstance.IsListening) { 131 145 return; 132 146 } … … 135 149 Interlocked.Increment (ref currentHandlers); 136 150 137 // MicroStopwatch msw = new MicroStopwatch ();138 151 #if ENABLE_PROFILER 139 152 UnityEngine.Profiling.Profiler.BeginThreadProfiling ("AllocsMods", "WebRequest"); 140 HttpListenerContext ctx = _listener.EndGetContext (_result);153 HttpListenerContext ctx = listenerInstance.EndGetContext (_result); 141 154 try { 142 155 #else 143 HttpListenerContext ctx = listener .EndGetContext (_result);144 listener .BeginGetContext (HandleRequest, listener);156 HttpListenerContext ctx = listenerInstance.EndGetContext (_result); 157 listenerInstance.BeginGetContext (HandleRequest, listenerInstance); 145 158 #endif 146 159 try { … … 149 162 response.SendChunked = false; 150 163 151 response.ProtocolVersion = HttpProtocolVersion;164 response.ProtocolVersion = httpProtocolVersion; 152 165 153 166 #if ENABLE_PROFILER … … 179 192 } 180 193 181 if (request.Url.AbsolutePath.Length < 2) { 182 handlers ["/index.htm"].HandleRequest (request, response, conn, permissionLevel); 183 return; 184 } else { 185 foreach (KeyValuePair<string, PathHandler> kvp in handlers) { 186 if (request.Url.AbsolutePath.StartsWith (kvp.Key)) { 187 if (!kvp.Value.IsAuthorizedForHandler (conn, permissionLevel)) { 188 response.StatusCode = (int) HttpStatusCode.Forbidden; 189 if (conn != null) { 190 //Log.Out ("Web.HandleRequest: user '{0}' not allowed to access '{1}'", conn.SteamID, kvp.Value.ModuleName); 191 } 192 } else { 193 #if ENABLE_PROFILER 194 handlerSampler.Begin (); 195 #endif 196 kvp.Value.HandleRequest (request, response, conn, permissionLevel); 197 #if ENABLE_PROFILER 198 handlerSampler.End (); 199 #endif 200 } 201 202 return; 203 } 204 } 205 } 206 207 // Not really relevant for non-debugging purposes: 208 //Log.Out ("Error in Web.HandleRequest(): No handler found for path \"" + request.Url.AbsolutePath + "\""); 209 response.StatusCode = (int) HttpStatusCode.NotFound; 194 string requestPath = request.Url.AbsolutePath; 195 196 if (requestPath.Length < 2) { 197 response.Redirect (indexPagePath); 198 return; 199 } 200 201 ApplyPathHandler (requestPath, request, response, conn, permissionLevel); 202 210 203 } catch (IOException e) { 211 204 if (e.InnerException is SocketException) { 212 Log.Out ("Error in Web.HandleRequest(): Remote host closed connection: " + 213 e.InnerException.Message); 205 Log.Out ("Error in Web.HandleRequest(): Remote host closed connection: " + e.InnerException.Message); 214 206 } else { 215 207 Log.Out ("Error (IO) in Web.HandleRequest(): " + e); … … 219 211 Log.Exception (e); 220 212 } finally { 221 if ( ctx != null &&!ctx.Response.SendChunked) {213 if (!ctx.Response.SendChunked) { 222 214 ctx.Response.Close (); 223 215 } 224 225 // msw.Stop ();226 // totalHandlingTime += msw.ElapsedMicroseconds;227 // Log.Out ("Web.HandleRequest(): Took {0} µs", msw.ElapsedMicroseconds);228 216 Interlocked.Decrement (ref currentHandlers); 229 217 } 230 218 #if ENABLE_PROFILER 231 219 } finally { 232 _listener.BeginGetContext (HandleRequest, _listener);220 listenerInstance.BeginGetContext (HandleRequest, listenerInstance); 233 221 UnityEngine.Profiling.Profiler.EndThreadProfiling (); 234 222 } 235 223 #endif 224 } 225 226 public void ApplyPathHandler (string _requestPath, HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _con, 227 int _permissionLevel) { 228 for (int i = handlers.Count - 1; i >= 0; i--) { 229 AbsHandler handler = handlers [i]; 230 231 if (_requestPath.StartsWith (handler.UrlBasePath)) { 232 if (!handler.IsAuthorizedForHandler (_con, _permissionLevel)) { 233 _resp.StatusCode = (int)HttpStatusCode.Forbidden; 234 if (_con != null) { 235 //Log.Out ("Web.HandleRequest: user '{0}' not allowed to access '{1}'", _con.SteamID, handler.ModuleName); 236 } 237 } else { 238 #if ENABLE_PROFILER 239 handlerSampler.Begin (); 240 #endif 241 handler.HandleRequest (_requestPath, _req, _resp, _con, _permissionLevel); 242 #if ENABLE_PROFILER 243 handlerSampler.End (); 244 #endif 245 } 246 247 return; 248 } 249 } 250 251 // Not really relevant for non-debugging purposes: 252 //Log.Out ("Error in Web.HandleRequest(): No handler found for path \"" + _requestPath + "\""); 253 _resp.StatusCode = (int) HttpStatusCode.NotFound; 236 254 } 237 255 … … 239 257 _con = null; 240 258 241 string sessionId = null; 242 if (_req.Cookies ["sid"] != null) { 243 sessionId = _req.Cookies ["sid"].Value; 244 } 245 259 string sessionId = _req.Cookies ["sid"]?.Value; 260 261 IPEndPoint reqRemoteEndPoint = _req.RemoteEndPoint; 262 if (reqRemoteEndPoint == null) { 263 Log.Warning ("No RemoteEndPoint on web request"); 264 return guestPermissionLevel; 265 } 266 246 267 if (!string.IsNullOrEmpty (sessionId)) { 247 WebConnection con = connectionHandler.IsLoggedIn (sessionId, _req.RemoteEndPoint.Address); 248 if (con != null) { 249 _con = con; 268 _con = connectionHandler.IsLoggedIn (sessionId, reqRemoteEndPoint.Address); 269 if (_con != null) { 250 270 return GameManager.Instance.adminTools.GetUserPermissionLevel (_con.UserId); 251 271 } 252 272 } 253 273 254 string remoteEndpointString = _req.RemoteEndPoint.ToString ();274 string remoteEndpointString = reqRemoteEndPoint.ToString (); 255 275 256 276 if (_req.QueryString ["adminuser"] != null && _req.QueryString ["admintoken"] != null) { … … 264 284 } 265 285 266 if (_req.Url.AbsolutePath.StartsWith ("/session/verify", StringComparison.OrdinalIgnoreCase)) { 267 try { 268 ulong id = OpenID.Validate (_req); 269 if (id > 0) { 270 WebConnection con = connectionHandler.LogIn (id, _req.RemoteEndPoint.Address); 271 _con = con; 272 int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId); 273 Log.Out ("Steam OpenID login from {0} with ID {1}, permission level {2}", 274 remoteEndpointString, con.UserId, level); 275 return level; 276 } 277 278 Log.Out ("Steam OpenID login failed from {0}", remoteEndpointString); 279 } catch (Exception e) { 280 Log.Error ("Error validating login:"); 281 Log.Exception (e); 282 } 283 } 284 285 return GUEST_PERMISSION_LEVEL; 286 return guestPermissionLevel; 286 287 } 287 288
Note:
See TracChangeset
for help on using the changeset viewer.