/// <summary> /// Initializes a marker for the referenced DataBoundView at the specified index /// </summary> /// <param name="view">Relevant DataBoundView object</param> /// <param name="index">Starting index of the @ tag</param> public Marker(DataBoundView view, int index) { this.instance = view; this.index = index; this.endIndex = instance.html.IndexOf("@", index + 1); if (endIndex == -1) { throw new Exception("Invalid view syntax at index " + index + ", no closing @ tag!"); } }
/// <summary> /// Gets a byte representation of the data requested in this HttpListenerContext request /// </summary> /// <param name="sender">Sender of the call</param> /// <param name="context">Context of the HTTP request</param> /// <param name="controllers">Relevant controllers to be searched for methods</param> /// <returns>a byte representation of the data requested in this HttpListenerContext request</returns> public static byte[] handleResponse(SaneServer sender, HttpListenerContext context, List<Type> controllers) { List<HttpArgument> arguments = new List<HttpArgument>(); MethodInfo[][] info = controllers.Select((g) => (g.GetMethods().Where((x) => (x.GetCustomAttribute<ControllerAttribute>() != null || x.GetCustomAttribute<DataBoundViewAttribute>() != null)).ToArray())).ToArray(); List<MethodInfo> methods = new List<MethodInfo>(); for (int i = 0; i < info.Length; i++) { for (int j = 0; j < info[i].Length; j++) { methods.Add(info[i][j]); } } foreach (String key in context.Request.QueryString.AllKeys) { arguments.Add(new HttpArgument(key, context.Request.QueryString.GetValues(key).First())); } byte[] returned = new byte[] { }; foreach (MethodInfo method in methods) { ControllerAttribute attribute = method.GetCustomAttribute<ControllerAttribute>(); if (attribute == null) { continue; } String trimmed = context.Request.RawUrl.Substring(0, context.Request.RawUrl.LastIndexOf("/") + 1); if ((attribute.path.Substring(0).Equals(trimmed)) && (attribute.verb.Equals(context.Request.HttpMethod))) { try { ParameterInfo[] parameters = method.GetParameters(); Dictionary<ParameterInfo, String> match = new Dictionary<ParameterInfo, String>(); foreach (ParameterInfo parameter in parameters) { foreach (HttpArgument argument in arguments) { if (argument.key.Equals(parameter.Name)) { match[parameter] = argument.value; } } } object[] finalized = new object[parameters.Length]; finalized[0] = context; if (context.Request.HasEntityBody) { finalized[1] = new StreamReader(context.Request.InputStream).ReadToEnd(); } else { finalized[1] = String.Empty; } for (int i = 2; i < parameters.Length; i++) { finalized[i] = (match.ContainsKey(parameters[i])) ? match[parameters[i]] : null; } context.Response.ContentType = attribute.contentType; if (method.ReturnType.Equals((new byte[] { }).GetType())) { return (byte[])method.Invoke(null, finalized); } else { return Encoding.UTF8.GetBytes(method.Invoke(null, finalized) + ""); } } catch (Exception e) { context.Response.ContentType = attribute.contentType; if (sender.GetErrorHandler() != null) { context.Response.StatusCode = 400; SaneErrorEventArgs args = new SaneErrorEventArgs(ResponseErrorReason.INTERNAL_API_THROW, e, false, ""); sender.GetErrorHandler()(null, args); if (args.Propogate) { return Encoding.UTF8.GetBytes(args.Response); } else { return new byte[] { }; } } else { context.Response.StatusCode = 400; return Encoding.UTF8.GetBytes("An error occured processing your request, and no error handler is currently set!"); } } } else if ((attribute.path.Substring(0).Equals(trimmed))) { if (sender.GetErrorHandler() != null) { context.Response.StatusCode = 400; SaneErrorEventArgs args = new SaneErrorEventArgs(ResponseErrorReason.INCORRECT_API_TYPE, new Exception("Incorrect API request type! Got " + context.Request.HttpMethod + ", expected " + attribute.verb + "!"), false, ""); sender.GetErrorHandler()(null, args); if (args.Propogate) { return Encoding.UTF8.GetBytes(args.Response); } else { return new byte[] { }; } } else { context.Response.StatusCode = 400; return Encoding.UTF8.GetBytes("An error occured processing your request, and no error handler is currently set!"); } } } Assembly assembly = Assembly.GetEntryAssembly(); XmlDocument structure = sender.GetViewStructure(); XmlNodeList resources = structure.SelectNodes("view/resource"); String request = context.Request.RawUrl.Substring(1).Replace("/", "."); XmlNode homePage = null; XmlNode notFound = null; foreach (XmlNode node in resources) { if (request.Equals(node.Attributes["path"].Value.Replace("/", "."))) { context.Response.ContentType = node.Attributes["content-type"].Value; byte[] clientData = Utility.fetchForClient(assembly, node.Attributes["location"].Value); foreach (MethodInfo method in methods) { DataBoundViewAttribute attribute = method.GetCustomAttribute<DataBoundViewAttribute>(); if (attribute == null) continue; if ((attribute.path.Equals(context.Request.RawUrl))) { Object binding = method.Invoke(null, new object[] { context }); DataBoundView boundView = new DataBoundView(clientData, binding); return Encoding.UTF8.GetBytes(boundView.html); } } return clientData; } if (node.Attributes["situational"] != null) { String value = node.Attributes["situational"].Value; if (value.Equals("homepage")) { homePage = node; } else if (value.Equals("404")) { notFound = node; } } } if (context.Request.RawUrl.Trim().Length <= 1) { context.Response.ContentType = "text/html"; byte[] clientData = new byte[] { }; if (homePage != null) { clientData = Utility.fetchForClient(assembly, homePage.Attributes["location"].Value.Replace("/", ".")); foreach (MethodInfo method in methods) { DataBoundViewAttribute attribute = method.GetCustomAttribute<DataBoundViewAttribute>(); if (attribute == null) continue; if ((attribute.path.Substring(1).Equals(homePage.Attributes["path"].Value))) { Object binding = method.Invoke(null, new object[] { context }); DataBoundView boundView = new DataBoundView(clientData, binding); return Encoding.UTF8.GetBytes(boundView.html); } } } return clientData; } context.Response.StatusCode = 404; context.Response.ContentType = "text/html"; byte[] ret = new byte[] { }; if (notFound != null) { ret = Utility.fetchForClient(assembly, notFound.Attributes["location"].Value.Replace("/", ".")); foreach (MethodInfo method in methods) { DataBoundViewAttribute attribute = method.GetCustomAttribute<DataBoundViewAttribute>(); if (attribute == null) continue; if ((attribute.path.Substring(1).Equals(notFound.Attributes["path"].Value))) { Object binding = method.Invoke(null, new object[] { context }); DataBoundView boundView = new DataBoundView(ret, binding); return Encoding.UTF8.GetBytes(boundView.html); } } } return ret; }