source: TFP-WebServer/WebServer/src/UrlHandlers/ApiHandler.cs@ 498

Last change on this file since 498 was 487, checked in by alloc, 5 months ago

1.1.0.1 Release for V 1.0

File size: 4.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Net;
4using System.Reflection;
5using Webserver.WebAPI;
6
7namespace Webserver.UrlHandlers {
8 public class ApiHandler : AbsHandler {
9 private readonly Dictionary<string, AbsWebAPI> apis = new CaseInsensitiveStringDictionary<AbsWebAPI> ();
10
11 public ApiHandler () : base (null) {
12 }
13
14 private static readonly Type[] apiWithParentCtorTypes = { typeof (Web) };
15 private static readonly object[] apiWithParentCtorArgs = new object[1];
16 private static readonly Type[] apiEmptyCtorTypes = { };
17 private static readonly object[] apiEmptyCtorArgs = { };
18
19 public override void SetBasePathAndParent (Web _parent, string _relativePath) {
20 base.SetBasePathAndParent (_parent, _relativePath);
21
22 apiWithParentCtorArgs[0] = _parent;
23
24 ReflectionHelpers.FindTypesImplementingBase (typeof (AbsWebAPI), apiFoundCallback);
25
26 // Permissions that don't map to a real API
27 addApi (new Null ("viewallclaims"));
28 addApi (new Null ("viewallplayers"));
29 }
30
31 private void apiFoundCallback (Type _type) {
32 ConstructorInfo ctor = _type.GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
33 apiWithParentCtorTypes, null);
34 if (ctor != null) {
35 AbsWebAPI apiInstance = (AbsWebAPI)ctor.Invoke (apiWithParentCtorArgs);
36 addApi (apiInstance);
37 return;
38 }
39
40 ctor = _type.GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
41 apiEmptyCtorTypes, null);
42 if (ctor != null) {
43 AbsWebAPI apiInstance = (AbsWebAPI)ctor.Invoke (apiEmptyCtorArgs);
44 addApi (apiInstance);
45 }
46 }
47
48 private void addApi (AbsWebAPI _api) {
49 apis.Add (_api.Name, _api);
50 parent.OpenApiHelpers.LoadOpenApiSpec (_api);
51 }
52
53 private static readonly UnityEngine.Profiling.CustomSampler apiHandlerSampler = UnityEngine.Profiling.CustomSampler.Create ("API_Handler");
54
55 private bool HandleCors (RequestContext _context) {
56 _context.Request.Headers.TryGetValue ("Origin", out string origin);
57 _context.Response.AddHeader ("Access-Control-Allow-Origin", origin ?? "*");
58
59 if (_context.Method != ERequestMethod.OPTIONS) {
60 return false;
61 }
62
63 if (!_context.Request.Headers.TryGetValue ("Access-Control-Request-Method", out _)) {
64 return false;
65 }
66
67 _context.Response.AddHeader ("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS, HEAD");
68 _context.Response.AddHeader ("Access-Control-Allow-Headers", "X-SDTD-API-TOKENNAME, X-SDTD-API-SECRET");
69 _context.Response.AddHeader ("Access-Control-Allow-Credentials", "true");
70 return true;
71 }
72
73 public override void HandleRequest (RequestContext _context) {
74
75 string apiName;
76 string subPath = null;
77
78 int pathSeparatorIndex = _context.RequestPath.IndexOf ('/', urlBasePath.Length);
79 if (pathSeparatorIndex >= 0) {
80 apiName = _context.RequestPath.Substring (urlBasePath.Length, pathSeparatorIndex - urlBasePath.Length);
81 subPath = _context.RequestPath.Substring (pathSeparatorIndex + 1);
82 } else {
83 apiName = _context.RequestPath.Substring (urlBasePath.Length);
84 }
85
86 if (!apis.TryGetValue (apiName, out AbsWebAPI api)) {
87 Log.Warning ($"[Web] In {nameof(ApiHandler)}.HandleRequest(): No handler found for API \"{apiName}\"");
88 _context.Response.StatusCode = (int) HttpStatusCode.NotFound;
89 return;
90 }
91
92 // CORS specific stuff
93 if (HandleCors (_context)) {
94 return;
95 }
96 // CORS end
97
98 _context.RequestPath = subPath;
99
100 if (!api.Authorized (_context)) {
101 _context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
102 if (_context.Connection != null) {
103 //Log.Out ($"{nameof(ApiHandler)}: user '{user.SteamID}' not allowed to execute '{apiName}'");
104 }
105
106 return;
107 }
108
109 try {
110 apiHandlerSampler.Begin ();
111 api.HandleRequest (_context);
112 apiHandlerSampler.End ();
113 } catch (Exception e) {
114 Log.Error ($"[Web] In {nameof(ApiHandler)}.HandleRequest(): Handler {api.Name} threw an exception:");
115 Log.Exception (e);
116 _context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
117 }
118 }
119 }
120}
Note: See TracBrowser for help on using the repository browser.