Skip to content

Commit d5ef884

Browse files
Add Base controller class for Rest services.
1 parent a64b1a9 commit d5ef884

File tree

1 file changed

+375
-0
lines changed

1 file changed

+375
-0
lines changed
Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Net.Http;
6+
using System.Text;
7+
using GeneXus.Application;
8+
using GeneXus.Configuration;
9+
using GeneXus.Data;
10+
using GeneXus.Http;
11+
using GeneXus.Metadata;
12+
using GeneXus.Security;
13+
using Microsoft.AspNetCore.Http;
14+
using Microsoft.AspNetCore.Mvc;
15+
16+
namespace GeneXus.Utils
17+
{
18+
public class GxRestService : ControllerBase
19+
{
20+
static readonly IGXLogger log = GXLoggerFactory.GetLogger<GxRestService>();
21+
22+
internal const string WARNING_HEADER = "Warning";
23+
protected IGxContext context;
24+
protected string permissionPrefix;
25+
protected string permissionMethod;
26+
bool runAsMain = true;
27+
28+
protected GxRestService()
29+
{
30+
context = GxContext.CreateDefaultInstance();
31+
if (GXUtil.CompressResponse())
32+
GXUtil.SetGZip(HttpContext);
33+
}
34+
protected void Cleanup()
35+
{
36+
ServiceHeaders();
37+
if (runAsMain)
38+
context.CloseConnections();
39+
}
40+
protected bool RunAsMain
41+
{
42+
get { return runAsMain; }
43+
set { runAsMain = value; }
44+
}
45+
//Convert GxUnknownObjectCollection of Object[] to GxUnknownObjectCollection of GxSimpleCollections
46+
protected GxUnknownObjectCollection TableHashList(GxUnknownObjectCollection tableHashList)
47+
{
48+
GxUnknownObjectCollection result = new GxUnknownObjectCollection();
49+
if (tableHashList != null && tableHashList.Count > 0)
50+
{
51+
foreach (object[] list in tableHashList)
52+
{
53+
GxStringCollection tableHash = new GxStringCollection();
54+
foreach (string data in list)
55+
{
56+
tableHash.Add(data);
57+
}
58+
result.Add(tableHash);
59+
}
60+
}
61+
return result;
62+
}
63+
64+
protected string EmptyParm(string parmValue)
65+
{
66+
if (string.IsNullOrEmpty(parmValue) || parmValue.Equals("gxempty", StringComparison.OrdinalIgnoreCase))
67+
return string.Empty;
68+
else
69+
return parmValue;
70+
}
71+
protected string RestStringParameter(string parameterName, string parameterValue)
72+
{
73+
try
74+
{
75+
if (HttpContext.Request.Query.TryGetValue(parameterName, out var value))
76+
return value.FirstOrDefault();
77+
else
78+
return parameterValue;
79+
}
80+
catch (Exception)
81+
{
82+
return parameterValue;
83+
}
84+
}
85+
protected bool RestParameter(string parameterName, string parameterValue)
86+
{
87+
try
88+
{
89+
if (HttpContext.Request.Query.TryGetValue(parameterName, out var value))
90+
return value.FirstOrDefault().Equals(parameterValue, StringComparison.OrdinalIgnoreCase);
91+
return false;
92+
}
93+
catch (Exception)
94+
{
95+
return false;
96+
}
97+
}
98+
/*public void UploadImpl(Stream stream)
99+
{
100+
GXObjectUploadServices gxobject = new GXObjectUploadServices(context);
101+
IncomingWebRequestContext request = WebOperationContext.Current.IncomingRequest;
102+
gxobject.WcfExecute(stream, request.ContentType, request.ContentLength, request.Headers[HttpHeader.XGXFILENAME]);
103+
}*/
104+
protected void ErrorCheck(IGxSilentTrn trn)
105+
{
106+
if (trn.Errors() == 1)
107+
{
108+
msglist msg = trn.GetMessages();
109+
if (msg.Count > 0)
110+
{
111+
msglistItem msgItem = (msglistItem)msg[0];
112+
if (msgItem.gxTpr_Id.Contains("NotFound"))
113+
HttpHelper.SetError(HttpContext, HttpStatusCode.NotFound.ToString(HttpHelper.INT_FORMAT), msgItem.gxTpr_Description);
114+
else if (msgItem.gxTpr_Id.Contains("WasChanged"))
115+
HttpHelper.SetError(HttpContext, HttpStatusCode.Conflict.ToString(HttpHelper.INT_FORMAT), msgItem.gxTpr_Description);
116+
else
117+
HttpHelper.SetError(HttpContext, HttpStatusCode.BadRequest.ToString(HttpHelper.INT_FORMAT), msgItem.gxTpr_Description);
118+
}
119+
}
120+
121+
}
122+
protected void SetMessages(msglist messages)
123+
{
124+
StringBuilder header = new StringBuilder();
125+
bool emptyHeader = true, encoded=false;
126+
const string SystemMsg = "System";
127+
const string UserMsg = "User";
128+
string typeMsg;
129+
130+
foreach (msglistItem msg in messages)
131+
{
132+
if (msg.gxTpr_Type == 0)
133+
{
134+
string value = msg.gxTpr_Description;
135+
encoded = false;
136+
if (GXUtil.ContainsNoAsciiCharacter(value))
137+
{
138+
value = GXUtil.UrlEncode(value);
139+
encoded = true;
140+
}
141+
typeMsg = msg.IsGxMessage ? SystemMsg : UserMsg;
142+
143+
header.AppendFormat("{0}299 {1} \"{2}{3}:{4}\"", emptyHeader ? string.Empty:",", context.GetServerName(), encoded ? GxRestPrefix.ENCODED_PREFIX : string.Empty, typeMsg, value);
144+
if (emptyHeader)
145+
{
146+
emptyHeader = false;
147+
}
148+
}
149+
}
150+
if (!emptyHeader)
151+
{
152+
AddHeader(WARNING_HEADER, StringUtil.Sanitize(header.ToString(), StringUtil.HttpHeaderWhiteList));
153+
}
154+
}
155+
protected void SetError(string code, string message)
156+
{
157+
HttpHelper.SetError(HttpContext, code, message);
158+
}
159+
protected void WebException(Exception ex)
160+
{
161+
GXLogging.Error(log, "Failed to complete execution of Rest Service:", ex);
162+
163+
if (ex is FormatException)
164+
{
165+
HttpHelper.SetUnexpectedError(HttpContext, HttpStatusCode.BadRequest, ex);
166+
}
167+
else
168+
{
169+
HttpHelper.SetUnexpectedError(HttpContext, HttpStatusCode.InternalServerError, ex);
170+
}
171+
}
172+
173+
protected bool IsAuthenticated(string synchronizer)
174+
{
175+
GXLogging.Debug(log, "IsMainAuthenticated synchronizer:" + synchronizer);
176+
bool validSynchronizer = false;
177+
try
178+
{
179+
if (!string.IsNullOrEmpty(synchronizer))
180+
{
181+
string nspace;
182+
if (!Config.GetValueOf("AppMainNamespace", out nspace))
183+
nspace = "GeneXus.Programs";
184+
string assemblyName = synchronizer.ToLower();
185+
string restServiceName = nspace + "." + assemblyName + "_services";
186+
GxRestService synchronizerService = (GxRestService)ClassLoader.GetInstance(assemblyName, restServiceName, null);
187+
if (synchronizerService!=null && synchronizerService.IsSynchronizer)
188+
{
189+
validSynchronizer = true;
190+
return IsAuthenticated(synchronizerService.IntegratedSecurityLevel, synchronizerService.IntegratedSecurityEnabled, synchronizerService.ExecutePermissionPrefix);
191+
}
192+
}
193+
return false;
194+
}
195+
catch (Exception ex)
196+
{
197+
GXLogging.Error(log, ex, "IsMainAuthenticated error ");
198+
return false;
199+
}
200+
finally
201+
{
202+
if (!validSynchronizer)
203+
HttpHelper.SetError(HttpContext, "0", "Invalid Synchronizer " + synchronizer);
204+
}
205+
}
206+
protected bool IsAuthenticated()
207+
{
208+
return IsAuthenticated(IntegratedSecurityLevel, IntegratedSecurityEnabled, permissionPrefix);
209+
}
210+
private bool IsAuthenticated(GAMSecurityLevel objIntegratedSecurityLevel, bool objIntegratedSecurityEnabled, string objPermissionPrefix)
211+
{
212+
if (!objIntegratedSecurityEnabled)
213+
{
214+
return true;
215+
}
216+
else {
217+
String token = GetHeader("Authorization");
218+
if (token == null)
219+
{
220+
HttpHelper.SetError(HttpContext, "0", "This service needs an Authorization Header");
221+
return false;
222+
}
223+
else
224+
{
225+
token = token.Replace("OAuth ", "");
226+
if (objIntegratedSecurityLevel == GAMSecurityLevel.SecurityLow)
227+
{
228+
bool isOK;
229+
GxResult result = GxSecurityProvider.Provider.checkaccesstoken(context, token, out isOK);
230+
if (!isOK)
231+
{
232+
HttpHelper.SetGamError(HttpContext, result.Code, result.Description);
233+
return false;
234+
}
235+
}
236+
else if (objIntegratedSecurityLevel == GAMSecurityLevel.SecurityHigh)
237+
{
238+
bool sessionOk, permissionOk;
239+
GxResult result = GxSecurityProvider.Provider.checkaccesstokenprm(context, token, objPermissionPrefix, out sessionOk, out permissionOk);
240+
if (permissionOk)
241+
{
242+
return true;
243+
}
244+
else
245+
{
246+
HttpHelper.SetGamError(HttpContext, result.Code, result.Description);
247+
if (sessionOk)
248+
{
249+
SetStatusCode(HttpStatusCode.Forbidden);
250+
}
251+
else
252+
{
253+
AddHeader(HttpHeader.AUTHENTICATE_HEADER, StringUtil.Sanitize(HttpHelper.OatuhUnauthorizedHeader(context.GetServerName(), result.Code, result.Description), StringUtil.HttpHeaderWhiteList));
254+
SetStatusCode(HttpStatusCode.Unauthorized);
255+
}
256+
return false;
257+
}
258+
}
259+
}
260+
return true;
261+
}
262+
}
263+
protected void SetStatusCode(HttpStatusCode code)
264+
{
265+
if (HttpContext != null)
266+
{
267+
HttpContext.Response.StatusCode = (int)code;
268+
}
269+
}
270+
IHeaderDictionary GetHeaders()
271+
{
272+
if (HttpContext != null)
273+
{
274+
return HttpContext.Request.Headers;
275+
}
276+
else return null;
277+
}
278+
string GetHeader(string header)
279+
{
280+
if (HttpContext != null)
281+
{
282+
return HttpContext.Request.Headers[header];
283+
}
284+
else return null;
285+
}
286+
bool IsPost()
287+
{
288+
if (HttpContext != null)
289+
{
290+
return HttpMethod.Post.Method == HttpContext.Request.GetMethod();
291+
}
292+
else return false;
293+
}
294+
void AddHeader(string header, string value)
295+
{
296+
if (HttpContext != null)
297+
{
298+
HttpContext.Response.Headers[header]= value;
299+
}
300+
}
301+
protected bool ProcessHeaders(string queryId)
302+
{
303+
304+
IHeaderDictionary headers = GetHeaders();
305+
String language = null, theme = null, etag = null;
306+
if (headers != null)
307+
{
308+
language = headers["GeneXus-Language"];
309+
theme = headers["GeneXus-Theme"];
310+
if (!IsPost())
311+
etag = headers["If-Modified-Since"];
312+
}
313+
314+
if (!string.IsNullOrEmpty(language))
315+
context.SetLanguage(language);
316+
317+
if (!string.IsNullOrEmpty(theme))
318+
context.SetTheme(theme);
319+
320+
DateTime dt = HTMLDateToDatetime(etag);
321+
DateTime newDt;
322+
DataUpdateStatus status;
323+
if (etag == null)
324+
{
325+
status = DataUpdateStatus.Invalid;
326+
GxSmartCacheProvider.CheckDataStatus(queryId, dt, out newDt);
327+
}
328+
else
329+
{
330+
status = GxSmartCacheProvider.CheckDataStatus(queryId, dt, out newDt);
331+
}
332+
AddHeader("Last-Modified", dateTimeToHTMLDate(newDt));
333+
334+
if (status == DataUpdateStatus.UpToDate)
335+
{
336+
SetStatusCode(HttpStatusCode.NotModified);
337+
return false;
338+
}
339+
return true;
340+
}
341+
342+
343+
344+
private void SendCacheHeaders()
345+
{
346+
if (string.IsNullOrEmpty(context.GetHeader(HttpHeader.CACHE_CONTROL)))
347+
AddHeader("Cache-Control", HttpHelper.CACHE_CONTROL_HEADER_NO_CACHE);
348+
}
349+
private void ServiceHeaders()
350+
{
351+
SendCacheHeaders();
352+
if (HttpContext != null)
353+
{
354+
HttpHelper.CorsHeaders(HttpContext);
355+
}
356+
357+
}
358+
DateTime HTMLDateToDatetime(string s)
359+
{
360+
// Date Format: RFC 1123
361+
DateTime dt;
362+
if (DateTime.TryParse(s, DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.AdjustToUniversal, out dt))
363+
return dt;
364+
return DateTime.MinValue;
365+
}
366+
string dateTimeToHTMLDate(DateTime dt)
367+
{
368+
return dt.ToUniversalTime().ToString(DateTimeFormatInfo.InvariantInfo.RFC1123Pattern, DateTimeFormatInfo.InvariantInfo);
369+
}
370+
protected virtual bool IsSynchronizer { get { return false; } }
371+
protected virtual bool IntegratedSecurityEnabled { get { return false; } }
372+
protected virtual GAMSecurityLevel IntegratedSecurityLevel { get { return 0; } }
373+
protected virtual string ExecutePermissionPrefix { get { return string.Empty; } }
374+
}
375+
}

0 commit comments

Comments
 (0)