/* * Called to handle a given web request. The system uses IHttpRequest to allow for different web server * systems. It checks to see if the url is for jquery,json or backbone, if none of those, it generates the required model * javascript for the given url, as specified by an attribute or attributes in Models, that define the * url that the model/view/collection javascript is available on. * If the call is not for javascript it processes the given action using the http method (GET = load, * DELETE = delete, POST = create, PUT = update, SELECT = SelectList, SMETHOD = StaticMethodCall, METHOD = MethodCall) */ public static void HandleRequest(IHttpRequest request) { Logger.Debug("Handling backbone request for path " + request.URL.ToString()); int status=-1; string message=null; bool allowNullResponse = false; if (request.URL.AbsolutePath.EndsWith(".js") && request.Method.ToUpper() == "GET") { if (request.IsJsURLAllowed(Uri.UnescapeDataString(request.URL.AbsolutePath), out status, out message)) { message = null; request.SetResponseContentType("text/javascript"); if (Uri.UnescapeDataString(request.URL.AbsolutePath) == (_jqueryURL == null ? "" : _jqueryURL)) { Logger.Trace("Sending jquery javascript response through backbone handler"); request.SetResponseStatus(200); request.WriteContent(Utility.ReadEmbeddedResource("Org.Reddragonit.BackBoneDotNet.resources.jquery.min.js",false)); request.SendResponse(); } else if (Uri.UnescapeDataString(request.URL.AbsolutePath) == (_jsonURL == null ? "" : _jsonURL)) { Logger.Trace("Sending json javascript response through backbone handler"); request.SetResponseStatus(200); request.WriteContent(Utility.ReadEmbeddedResource("Org.Reddragonit.BackBoneDotNet.resources.json2.min.js",false)); request.SendResponse(); } else if (Uri.UnescapeDataString(request.URL.AbsolutePath) == (_backboneURL == null ? "" : _backboneURL)) { Logger.Trace("Sending modified backbone javascript response through backbone handler"); request.SetResponseStatus(200); request.WriteContent(Utility.ReadEmbeddedResource("Org.Reddragonit.BackBoneDotNet.resources.backbone_combined.min.js",false)); request.SendResponse(); } else { bool found = false; lock (_CachedJScript) { if (_CachedJScript.ContainsKey(request.URL.Host + Uri.UnescapeDataString(request.URL.AbsolutePath))) { Logger.Trace("Sending cached javascript response for path " + request.URL.Host + request.URL.AbsolutePath); found = true; request.SetResponseStatus(200); request.WriteContent((string)_CachedJScript[request.URL.Host + Uri.UnescapeDataString(request.URL.AbsolutePath)].Value); request.SendResponse(); } } if (!found) { Logger.Trace("Buidling model javascript for path " + request.URL.Host + Uri.UnescapeDataString(request.URL.AbsolutePath)); StringBuilder sb = new StringBuilder(); foreach (Type t in Utility.LocateTypeInstances(typeof(IModel))) { foreach (ModelJSFilePath mj in t.GetCustomAttributes(typeof(ModelJSFilePath), false)) { if ((mj.Host == "*" || mj.Host == request.URL.Host) && (mj.Path == Uri.UnescapeDataString(request.URL.AbsolutePath)||mj.MinPath==Uri.UnescapeDataString(request.URL.AbsolutePath))) { Logger.Trace("Appending model " + t.FullName + " to path " + request.URL.Host + Uri.UnescapeDataString(request.URL.AbsolutePath)); sb.Append(_GenerateModelJSFile(t, request.URL.Host, mj.MinPath == Uri.UnescapeDataString(request.URL.AbsolutePath) || Settings.Default.CompressAllJS)); } } } request.SetResponseStatus(200); request.WriteContent(sb.ToString()); lock (_CachedJScript) { if (!_CachedJScript.ContainsKey(request.URL.Host + request.URL.AbsolutePath)) _CachedJScript.Add(request.URL.Host + Uri.UnescapeDataString(request.URL.AbsolutePath), new CachedItemContainer(sb.ToString())); } request.SendResponse(); } } } else _SetSecurityError(out status, out message); } else { Object ret = null; switch (request.Method.ToUpper()) { case "GET": Logger.Trace("Attempting to handle GET request"); if (_RPC_SELECT.IsMatch(request.Method.ToUpper(), request.URL.Host, request.URL.AbsolutePath + (request.URL.Query != "" ? request.URL.Query : ""))) { Logger.Trace("Handling request as a model list method"); foreach (sModelListCall mlc in _ModelListCalls) { if (mlc.HandlesRequest(request)) { if (request.IsListAllowed(mlc.ModelType, out status, out message)) { message = null; ret = mlc.HandleRequest(request); } else _SetSecurityError(out status, out message); break; } } } else { if (_LoadAlls.ContainsKey(request.URL.Host + request.URL.AbsolutePath)) { Logger.Trace("Handling Load All request"); if (request.IsLoadAllAllowed(_LoadAlls[request.URL.Host + request.URL.AbsolutePath].DeclaringType, out status, out message)) { message = null; ret = _LoadAlls[request.URL.Host + request.URL.AbsolutePath].Invoke(null, new object[0]); } else _SetSecurityError(out status, out message); } else if (_LoadAlls.ContainsKey("*" + request.URL.AbsolutePath)) { Logger.Trace("Handling Load All request"); if (request.IsLoadAllAllowed(_LoadAlls["*" + request.URL.AbsolutePath].DeclaringType, out status, out message)) { message = null; ret = _LoadAlls["*" + request.URL.AbsolutePath].Invoke(null, new object[0]); } else _SetSecurityError(out status, out message); } else if (_Loads.ContainsKey(request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/")))) { Logger.Trace("Handling Load request"); if (request.IsLoadAllowed(_Loads[request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].DeclaringType, Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)), out status, out message)) { message = null; ret = _Loads[request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].Invoke(null, new object[] { Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)) }); } else _SetSecurityError(out status, out message); } else if (_Loads.ContainsKey("*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/")))) { Logger.Trace("Handling Load request"); if (request.IsLoadAllowed(_Loads["*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].DeclaringType, Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)), out status, out message)) { message = null; ret = _Loads["*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].Invoke(null, new object[] { Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)) }); } else _SetSecurityError(out status, out message); } } break; case "SELECT": Logger.Trace("Handling Select List request"); if (_SelectLists.ContainsKey(request.URL.Host + request.URL.AbsolutePath)) { foreach (sModelListCall mlc in _SelectLists[request.URL.Host + request.URL.AbsolutePath]) { if (mlc.HandlesRequest(request)) { if (request.IsSelectAllowed(mlc.ModelType, out status, out message)) { message = null; ret = mlc.HandlesRequest(request); } else _SetSecurityError(out status, out message); break; } } } else if (_SelectLists.ContainsKey("*" + request.URL.AbsolutePath)) { foreach (sModelListCall mlc in _SelectLists["*" + request.URL.AbsolutePath]) { if (mlc.HandlesRequest(request)) { if (request.IsSelectAllowed(mlc.ModelType, out status, out message)) { message = null; ret = mlc.HandleRequest(request); } else _SetSecurityError(out status, out message); break; } } } break; case "PUT": case "PATCH": Logger.Trace("Handling Put request"); if (_Loads.ContainsKey(request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/")))) { if (request.IsLoadAllowed(_Loads[request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].DeclaringType, Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)), out status, out message)) { message = null; ret = _Loads[request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].Invoke(null, new object[] { Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)) }); } else _SetSecurityError(out status, out message); } else if (_Loads.ContainsKey("*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/")))) { if (request.IsLoadAllowed(_Loads["*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].DeclaringType, Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)), out status, out message)) { message = null; ret = _Loads["*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].Invoke(null, new object[] { Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)) }); } else _SetSecurityError(out status, out message); } if (ret != null) { Hashtable ht = (Hashtable)JSON.JsonDecode(request.ParameterContent); if (request.IsUpdateAllowed((IModel)ret, ht, out status, out message)) { message = null; Hashtable IModelTypes = new Hashtable(); foreach (string str in ht.Keys) { if (str != "id") { if (ret.GetType().GetProperty(str).GetCustomAttributes(typeof(ReadOnlyModelProperty), true).Length == 0) { Type propType = ret.GetType().GetProperty(str).PropertyType; if (propType.IsArray) propType = propType.GetElementType(); else if (propType.IsGenericType) { if (propType.GetGenericTypeDefinition() == typeof(List<>)) propType = propType.GetGenericArguments()[0]; } var obj = _ConvertObjectToType(ht[str], ret.GetType().GetProperty(str).PropertyType); if (new List<Type>(propType.GetInterfaces()).Contains(typeof(IModel))) IModelTypes.Add(str, obj); ret.GetType().GetProperty(str).SetValue(ret, obj, new object[0]); } } } if (_UpdateMethods.ContainsKey(ret.GetType())) ret = _UpdateMethods[ret.GetType()].Invoke(ret, new object[0]); else ret = false; if ((bool)ret && IModelTypes.Count > 0) ret = IModelTypes; else if (!(bool)ret) ret = null; } else _SetSecurityError(out status, out message); } break; case "DELETE": Logger.Trace("Handling Delete request"); if (_Loads.ContainsKey(request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/")))) { if (request.IsLoadAllowed(_Loads[request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].DeclaringType, Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)), out status, out message)) { message = null; ret = _Loads[request.URL.Host + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].Invoke(null, new object[] { Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)) }); } else _SetSecurityError(out status, out message); } else if (_Loads.ContainsKey("*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/")))) { if (request.IsLoadAllowed(_Loads["*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].DeclaringType, Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)), out status, out message)) { message = null; ret = _Loads["*" + request.URL.AbsolutePath.Substring(0, request.URL.AbsolutePath.LastIndexOf("/"))].Invoke(null, new object[] { Uri.UnescapeDataString(request.URL.AbsolutePath.Substring(request.URL.AbsolutePath.LastIndexOf("/") + 1)) }); } else _SetSecurityError(out status, out message); } if (ret != null) { if (_DeleteMethods.ContainsKey(ret.GetType())) { if (request.IsDeleteAllowed(ret.GetType(), ((IModel)ret).id, out status, out message)) { message = null; ret = _DeleteMethods[ret.GetType()].Invoke(ret, new object[0]); } else _SetSecurityError(out status, out message); } else ret = null; } break; case "POST": Logger.Trace("Handling Post request"); Type t = null; if (_TypeMaps.ContainsKey(request.URL.Host + request.URL.AbsolutePath)) t = _TypeMaps[request.URL.Host + request.URL.AbsolutePath]; else if (_TypeMaps.ContainsKey("*"+request.URL.AbsolutePath)) t = _TypeMaps["*"+request.URL.AbsolutePath]; if (t != null) { Hashtable mht = (Hashtable)JSON.JsonDecode(request.ParameterContent); if (request.IsSaveAllowed(t, mht, out status, out message)) { message = null; IModel mod = (IModel)t.GetConstructor(Type.EmptyTypes).Invoke(new object[0]); foreach (string str in mht.Keys) { if (str != "id") { PropertyInfo pi = t.GetProperty(str); if (pi.CanWrite) t.GetProperty(str).SetValue(mod, _ConvertObjectToType(mht[str], t.GetProperty(str).PropertyType), new object[0]); } } if (_SaveMethods.ContainsKey(t)) { if ((bool)_SaveMethods[t].Invoke(mod, new object[0])) { ret = new Hashtable(); ((Hashtable)ret).Add("id", mod.id); } else { message = "Error saving model."; status = 500; ret = null; } } else ret = null; } else _SetSecurityError(out status, out message); } break; case "METHOD": case "SMETHOD": Hashtable pars = (Hashtable)JSON.JsonDecode(request.ParameterContent); string url = request.URL.AbsolutePath; string method = url.Substring(url.LastIndexOf("/")+1); url = url.Substring(0,url.Length-method.Length-1); List<MethodInfo> methods = new List<MethodInfo>(); if (request.Method.ToUpper() == "METHOD") { string id = url.Substring(url.LastIndexOf("/") + 1); url = url.Substring(0, url.Length - id.Length - 1); id = Uri.UnescapeDataString(id); if (_Loads.ContainsKey(request.URL.Host + url)) { if (request.IsLoadAllowed(_Loads[request.URL.Host + url].DeclaringType, id, out status, out message)) { message = null; ret = _Loads[request.URL.Host + url].Invoke(null, new object[] { id }); } else _SetSecurityError(out status, out message); } else if (_Loads.ContainsKey("*" + url)) { if (request.IsLoadAllowed(_Loads["*" + url].DeclaringType, id, out status, out message)) { message = null; ret = _Loads["*" + url].Invoke(null, new object[] { id }); } else _SetSecurityError(out status, out message); } if (ret != null) { if (request.IsExposedMethodAllowed((IModel)ret, method, pars, out status, out message)) { foreach (MethodInfo m in ret.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public)) { if (m.Name == method) { if (m.GetCustomAttributes(typeof(ExposedMethod), false).Length > 0) methods.Add(m); } } } else ret = null; } } else { ret = null; if (_ExposedMethods.ContainsKey(request.URL.Host + url + "/" + method)) methods.AddRange(_ExposedMethods[request.URL.Host + url + "/" + method]); else if (_ExposedMethods.ContainsKey("*" + url + "/" + method)) methods.AddRange(_ExposedMethods["*" + url + "/" + method]); if (methods.Count > 0) { if (!request.IsStaticExposedMethodAllowed(methods[0].DeclaringType, method, pars, out status, out message)) { methods.Clear(); _SetSecurityError(out status, out message); } } } if (methods.Count>0) { object[] opars = null; MethodInfo mi = null; if (pars == null || pars.Count == 0) { foreach (MethodInfo m in methods) { if (m.GetParameters().Length == 0) { mi = m; break; } } opars = new object[0]; } else { opars = new object[pars.Count]; foreach (MethodInfo m in methods) { if (m.GetParameters().Length == pars.Count) { bool isMethod = true; int index = 0; foreach (ParameterInfo pi in m.GetParameters()) { if (pars.ContainsKey(pi.Name)) opars[index] = _ConvertObjectToType(pars[pi.Name], pi.ParameterType); else { isMethod = false; break; } index++; } if (isMethod) { mi = m; break; } } } } if (mi == null) { message = "Unable to locate requested method to invoke"; status = 404; ret = null; } else if (mi.GetCustomAttributes(typeof(ExposedMethod), false).Length == 0) { message = "Unable to locate requested method to invoke"; status = 404; ret = null; } else { allowNullResponse = ((ExposedMethod)mi.GetCustomAttributes(typeof(ExposedMethod), false)[0]).AllowNullResponse; message = null; try { if (mi.ReturnType == typeof(void)) { mi.Invoke(ret, opars); ret = new object(); } else ret = mi.Invoke(ret, opars); } catch (Exception ex) { message = ex.Message; status = 500; } } } break; } request.SetResponseContentType("application/json"); if (ret != null || (allowNullResponse&&message==null)) { Logger.Trace("Request successfully handled, sending response"); request.SetResponseStatus(200); request.WriteContent(JSON.JsonEncode(_SetupAdditionalBackbonehash(ret,request))); request.SendResponse(); } else { if (message!=null){ request.SetResponseStatus(status); request.WriteContent(JSON.JsonEncode(message)); }else{ Logger.Trace("Handling of request failed, sending 404 response"); request.SetResponseStatus(404); request.WriteContent(JSON.JsonEncode("Not Found")); } request.SendResponse(); } } }