source: binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs@ 435

Last change on this file since 435 was 434, checked in by alloc, 19 months ago

Added permission management APIs

File size: 6.6 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Net;
5using Utf8Json;
6using Webserver.Permissions;
7
8namespace Webserver.WebAPI {
9 public abstract class AbsRestApi : AbsWebAPI {
10 private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize");
11
12 protected AbsRestApi (string _name = null) : this(null, _name) {
13 }
14
15 protected AbsRestApi (Web _parentWeb, string _name = null) : base(_parentWeb, _name) {
16 }
17
18 protected override void RegisterPermissions () {
19 AdminWebModules.Instance.AddKnownModule (new AdminWebModules.WebModule (CachedApiModuleName, DefaultPermissionLevel (),
20 DefaultMethodPermissionLevels (), true));
21 }
22
23 public sealed override void HandleRequest (RequestContext _context) {
24 IDictionary<string, object> inputJson = null;
25 byte[] jsonInputData = null;
26
27 if (_context.Request.HasEntityBody) {
28 Stream requestInputStream = _context.Request.InputStream;
29
30 jsonInputData = new byte[_context.Request.ContentLength64];
31 requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
32
33 try {
34 jsonDeserializeSampler.Begin ();
35 inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
36
37 // Log.Out ("JSON body:");
38 // foreach ((string key, object value) in inputJson) {
39 // Log.Out ($" - {key} = {value} ({value.GetType ()})");
40 // }
41
42 jsonDeserializeSampler.End ();
43 } catch (Exception e) {
44 jsonDeserializeSampler.End ();
45
46 SendEmptyResponse (_context, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
47 return;
48 }
49 }
50
51 try {
52 switch (_context.Method) {
53 case ERequestMethod.GET:
54 if (inputJson != null) {
55 SendEmptyResponse (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
56 return;
57 }
58
59 HandleRestGet (_context);
60 return;
61 case ERequestMethod.POST:
62 if (!AllowPostWithId && !string.IsNullOrEmpty (_context.RequestPath)) {
63 SendEmptyResponse (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
64 return;
65 }
66
67 if (inputJson == null) {
68 SendEmptyResponse (_context, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
69 return;
70 }
71
72 HandleRestPost (_context, inputJson, jsonInputData);
73 return;
74 case ERequestMethod.PUT:
75 if (string.IsNullOrEmpty (_context.RequestPath)) {
76 SendEmptyResponse (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
77 return;
78 }
79
80 if (inputJson == null) {
81 SendEmptyResponse (_context, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
82 return;
83 }
84
85 HandleRestPut (_context, inputJson, jsonInputData);
86 return;
87 case ERequestMethod.DELETE:
88 if (string.IsNullOrEmpty (_context.RequestPath)) {
89 SendEmptyResponse (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
90 return;
91 }
92
93 if (inputJson != null) {
94 SendEmptyResponse (_context, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
95 return;
96 }
97
98 HandleRestDelete (_context);
99 return;
100 default:
101 SendEmptyResponse (_context, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
102 return;
103 }
104 } catch (Exception e) {
105 SendEmptyResponse (_context, HttpStatusCode.InternalServerError, jsonInputData, "ERROR_PROCESSING", e);
106 }
107 }
108
109 protected virtual void HandleRestGet (RequestContext _context) {
110 SendEmptyResponse (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
111 }
112
113 protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
114 SendEmptyResponse (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
115 }
116
117 protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
118 SendEmptyResponse (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
119 }
120
121 protected virtual void HandleRestDelete (RequestContext _context) {
122 SendEmptyResponse (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
123 }
124
125 public override bool Authorized (RequestContext _context) {
126 AdminWebModules.WebModule module = AdminWebModules.Instance.GetModule (CachedApiModuleName);
127
128 if (module.LevelPerMethod == null) {
129 return module.LevelGlobal >= _context.PermissionLevel;
130 }
131
132 int perMethodLevel = module.LevelPerMethod [(int)_context.Method];
133 if (perMethodLevel == AdminWebModules.MethodLevelNotSupported) {
134 return false;
135 }
136
137 if (perMethodLevel != AdminWebModules.MethodLevelInheritGlobal) {
138 return perMethodLevel >= _context.PermissionLevel;
139 }
140
141 return module.LevelGlobal >= _context.PermissionLevel;
142 }
143
144 protected virtual bool AllowPostWithId => false;
145
146 /// <summary>
147 /// Define default permission levels per HTTP method as an array of levels. See <see cref="ERequestMethod"/> for the order of entries.
148 /// </summary>
149 /// <returns>Default permission levels for supported methods. See <see cref="AdminWebModules.MethodLevelNotSupported"/> and <see cref="AdminWebModules.MethodLevelInheritGlobal"/>.</returns>
150 public virtual int[] DefaultMethodPermissionLevels () => new[] {
151 AdminWebModules.MethodLevelNotSupported,
152 AdminWebModules.MethodLevelInheritGlobal,
153 AdminWebModules.MethodLevelInheritGlobal,
154 AdminWebModules.MethodLevelInheritGlobal,
155 AdminWebModules.MethodLevelInheritGlobal
156 };
157
158#region Helpers
159
160 protected static void PrepareEnvelopedResult (out JsonWriter _writer) {
161 WebUtils.PrepareEnvelopedResult (out _writer);
162 }
163
164 protected static void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK,
165 byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
166
167 WebUtils.SendEnvelopedResult (_context, ref _writer, _statusCode, _jsonInputData, _errorCode, _exception);
168 }
169
170 protected static void SendEmptyResponse (RequestContext _context, HttpStatusCode _statusCode = HttpStatusCode.OK, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
171 PrepareEnvelopedResult (out JsonWriter writer);
172 writer.WriteRaw (WebUtils.JsonEmptyData);
173 SendEnvelopedResult (_context, ref writer, _statusCode, _jsonInputData, _errorCode, _exception);
174 }
175
176#endregion
177 }
178}
Note: See TracBrowser for help on using the repository browser.