// Handles an incoming request private void HandleRequest(HttpListenerContext HttpContext) { string Result = ""; try { // Get request information var Request = HttpContext.Request; string RequestType = Request.HttpMethod; string Password = Request.Headers["Password"]; string MethodName = Request.Url.Segments[2].Replace("/", "").ToUpper(); int Version = int.Parse(Request.Url.Segments[1].Replace("/", "")); // Check if requested method exists var Methods = MethodContexts.GetMethods(MethodName); if (!Methods.Any()) { throw new InvalidOperationException("Invalid API method"); } // Loop through found methods // TODO - also check # of params needed when getting methods foreach (var Entry in Methods) { // Check request type // TODO - This looks ugly... Clean it up if ((Entry.Type == ApiRequestType.POST && RequestType != "POST") || (Entry.Type == ApiRequestType.GET && RequestType != "GET")) { continue; } // Check request version against context version if (!Entry.Context.CheckVersion(Version)) { continue; } // Check request validation if (Entry.RequiresValidation && Password != this.Password) { continue; } // Get method parameters var MethodParams = Entry.Method.GetParameters(); // Get request parameters object[] Params = new object[MethodParams.Length]; if (RequestType == "GET") { // Get our request's params directly from URL string string[] RequestParams = Request.Url.Segments.Skip(3).Select(x => x.Replace("/", "")).ToArray(); // Populate our parameters for (int i = 0; i < MethodParams.Length; i++) { // Check if this parameter is present in the request if (i < RequestParams.Length) { // Convert to method parameter type Params[i] = Convert.ChangeType(RequestParams[i], MethodParams[i].ParameterType); } // Otherwise default to a null value else { continue; } } } else if (RequestType == "POST") { // Get our request's params from the stream data var RequestParams = new Dictionary <string, dynamic>(); using (var Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { var Json = JsonConvert.DeserializeObject <JObject>(Reader.ReadToEnd()); RequestParams = new Dictionary <string, object>( Json.ToObject <IDictionary <string, object> >(), StringComparer.CurrentCultureIgnoreCase); } // Populate our parameters for (int i = 0; i < MethodParams.Length; i++) { // Check if this parameter is present in the request if (RequestParams.ContainsKey(MethodParams[i].Name)) { // Convert to method parameter type Params[i] = Convert.ChangeType(RequestParams[MethodParams[i].Name], MethodParams[i].ParameterType); } // Otherwise default to a null value else { continue; } } } // Try invoke method var Output = (string)Entry.Method.Invoke(Entry.Context, Params); // TODO - better (more efficient) way to catch errors, yikes if (JsonConvert.DeserializeObject <JObject>(Output).TryGetValue("error", out _)) { continue; } Result = Output; break; } // Check if result is empty if (string.IsNullOrEmpty(Result)) { throw new InvalidOperationException("Invalid API method"); } } // A known error was caught catch (InvalidOperationException e) { Result = new JObject { ["error"] = e.Message }.ToString(); } // Unable to parse this request catch { Result = new JObject { ["error"] = "Invalid request" }.ToString(); } // Populate a new HTTP header and send our response var Buffer = Encoding.UTF8.GetBytes(Result); var Response = HttpContext.Response; Response.ContentLength64 = Buffer.Length; using (var st = Response.OutputStream) st.Write(Buffer, 0, Buffer.Length); Response.Close(); }
// Finds a method in the list of method contexts // Handles an incoming request private void HandleRequest(HttpListenerContext HttpContext) { string Result = ""; try { // Get request information var Request = HttpContext.Request; string RequestType = Request.HttpMethod; string Password = Request.Headers["Password"]; // Check if requested method exists string MethodName = Request.Url.Segments[2].Replace("/", "").ToUpper(); if (!MethodContexts.TryGetMethod(MethodName, out var Method, out var Context, out var Validate)) { throw new InvalidOperationException("Invalid API method"); } // Check request's API version if (!int.TryParse(Request.Url.Segments[1].Replace("/", ""), out int Version) || !Context.CheckVersion(Version)) { throw new InvalidOperationException("Invalid API version"); } // Check request validation if (Validate && Password != this.Password) { throw new InvalidOperationException("Invalid password"); } // "GET" request if (RequestType == "GET") { // Get our request's params directly from URL string string[] Params = Request.Url.Segments.Skip(3).Select(x => x.Replace("/", "")).ToArray(); Logger.Debug($"[{Request.RemoteEndPoint.Address.ToString()} API] " + $"/{Version}/{MethodName}/{string.Join("/", Request.Url.Segments.Skip(3))}"); // Populate our parameters var Parameters = Method.GetParameters(); object[] MethodParams = new object[Parameters.Length]; for (int i = 0; i < Parameters.Length; i++) { if (i < Params.Length) { MethodParams[i] = Convert.ChangeType(Params[i], Parameters[i].ParameterType); } else { MethodParams[i] = null; } } // Invoke the requested method Result = (string)Method.Invoke(Context, MethodParams); } // "POST" request else if (RequestType == "POST") { // Get our request's params from the stream data string RequestBody = ""; using (var Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) RequestBody = Reader.ReadToEnd(); JObject Params = JsonConvert.DeserializeObject <JObject>(RequestBody); Logger.Debug($"[{Request.RemoteEndPoint.Address.ToString()} API] /{Version}/{MethodName}/"); // Invoke the requested method Result = (string)Method.Invoke(this, new object[] { Params }); } } // A known error was caught catch (InvalidOperationException e) { Result = $"{{'error':'{e.Message}'}}"; } // Unable to parse this request catch { Result = "{'error':'Invalid request'}"; } // Populate a new HTTP header and send our response var Buffer = Encoding.UTF8.GetBytes(Result); var Response = HttpContext.Response; Response.ContentLength64 = Buffer.Length; using (var st = Response.OutputStream) st.Write(Buffer, 0, Buffer.Length); Response.Close(); }