using System; using System.Collections.Generic; using System.Net; using System.Reflection; using Webserver.WebAPI; namespace Webserver.UrlHandlers { public class ApiHandler : AbsHandler { private readonly Dictionary apis = new CaseInsensitiveStringDictionary (); public ApiHandler () : base (null) { } private static readonly Type[] apiWithParentCtorTypes = { typeof (Web) }; private static readonly object[] apiWithParentCtorArgs = new object[1]; private static readonly Type[] apiEmptyCtorTypes = { }; private static readonly object[] apiEmptyCtorArgs = { }; public override void SetBasePathAndParent (Web _parent, string _relativePath) { base.SetBasePathAndParent (_parent, _relativePath); apiWithParentCtorArgs[0] = _parent; ReflectionHelpers.FindTypesImplementingBase (typeof (AbsWebAPI), apiFoundCallback); // Permissions that don't map to a real API addApi (new Null ("viewallclaims")); addApi (new Null ("viewallplayers")); } private void apiFoundCallback (Type _type) { ConstructorInfo ctor = _type.GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, (Binder)null, apiWithParentCtorTypes, (ParameterModifier[])null); if (ctor != null) { AbsWebAPI apiInstance = (AbsWebAPI)ctor.Invoke (apiWithParentCtorArgs); addApi (apiInstance); return; } ctor = _type.GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, (Binder)null, apiEmptyCtorTypes, (ParameterModifier[])null); if (ctor != null) { AbsWebAPI apiInstance = (AbsWebAPI)ctor.Invoke (apiEmptyCtorArgs); addApi (apiInstance); } } private void addApi (AbsWebAPI _api) { apis.Add (_api.Name, _api); parent.OpenApiHelpers.LoadOpenApiSpec (_api); } private static readonly UnityEngine.Profiling.CustomSampler apiHandlerSampler = UnityEngine.Profiling.CustomSampler.Create ("API_Handler"); public override void HandleRequest (RequestContext _context) { string apiName; string subPath = null; int pathSeparatorIndex = _context.RequestPath.IndexOf ('/', urlBasePath.Length); if (pathSeparatorIndex >= 0) { apiName = _context.RequestPath.Substring (urlBasePath.Length, pathSeparatorIndex - urlBasePath.Length); subPath = _context.RequestPath.Substring (pathSeparatorIndex + 1); } else { apiName = _context.RequestPath.Substring (urlBasePath.Length); } if (!apis.TryGetValue (apiName, out AbsWebAPI api)) { Log.Warning ($"[Web] In {nameof(ApiHandler)}.HandleRequest(): No handler found for API \"{apiName}\""); _context.Response.StatusCode = (int) HttpStatusCode.NotFound; return; } _context.RequestPath = subPath; if (!api.Authorized (_context)) { _context.Response.StatusCode = (int) HttpStatusCode.Forbidden; if (_context.Connection != null) { //Log.Out ($"{nameof(ApiHandler)}: user '{user.SteamID}' not allowed to execute '{apiName}'"); } return; } try { apiHandlerSampler.Begin (); api.HandleRequest (_context); apiHandlerSampler.End (); } catch (Exception e) { Log.Error ($"[Web] In {nameof(ApiHandler)}.HandleRequest(): Handler {api.Name} threw an exception:"); Log.Exception (e); _context.Response.StatusCode = (int) HttpStatusCode.InternalServerError; } } } }