/// <summary> /// Implements advice logic. /// Usually, advice must invoke context.Proceed() /// </summary> /// <param name="context">The method advice context.</param> /// <exception cref="System.InvalidOperationException"></exception> public void Advise(MethodAdviceContext context) { var invokedMethod = (MethodInfo)context.TargetMethod; var restCall = RestCall.FromMethod(invokedMethod); if (restCall == null) throw new NotImplementedException(); // first, replace the parameters // (not elegant way) var path = restCall.Path; var parameters = invokedMethod.GetParameters(); for (int parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++) { var parameter = context.Parameters[parameterIndex]; var literalParameter = parameter != null ? parameter.ToString() : ""; var literalParameterPlaceholder = "{" + parameters[parameterIndex].Name + "}"; path = path.Replace(literalParameterPlaceholder, literalParameter); } // then create the route and send the request var hostAddress = _hostAddress; if (hostAddress == null) { var serviceContractAttribute = context.TargetType.GetCustomAttribute<ServiceContractAttribute>(); hostAddress = new Uri(serviceContractAttribute.Namespace); } var target = DnsNameResolver.LocalResolve(hostAddress.Host); using (var stream = _route.Connect(target, hostAddress.Port).ToNetworkStream()) { var request = new HttpRequest(restCall.Verb, path) .AddHeader("Host", hostAddress.GetHostAndPort()) .AddHeader("Connection", "Close") .AddHeader("Proxy-Connection", "Keep-Alive"); request.Write(stream); var response = HttpResponse.FromStream(stream); if (response.StatusCode >= 400) { var errorText = response.ReadContentString(stream); throw new InvalidOperationException(errorText); } // handle return value if (invokedMethod.ReturnType != typeof(void)) { var contentString = response.ReadContentString(stream); using (var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString))) { var serializer = new DataContractJsonSerializer(invokedMethod.ReturnType); var result = serializer.ReadObject(contentStream); context.ReturnValue = result; } } } }
/// <summary> /// Parses html page and creates collection of biis controls from it /// </summary> /// <param name="path">URI path</param> /// <param name="directory">Directory on disk</param> /// <param name="request">Http request</param> /// <returns>Collection of all biis controls frm document</returns> public Dictionary<string, IBiisControl> GetControlsCollection(string path, string directory, HttpRequest request) { Dictionary<string, IBiisControl> controls = new Dictionary<string, IBiisControl>(); //Regex to find <biis: tag, find control type, its attributes and content Regex biisTagRegex = new Regex( "[\\s\\S]*<biis:(?<controll>[\\w]*)\\s((?:[\\w]*)=[\"\'](?:[^\"]*?['\"]|[^']*['\"])\\s*)(>(?<content>[\\s\\S]*?)<.biis:\\k<controll>>|.>)[\\s\\S]*", RegexOptions.IgnoreCase); //Regex to parse attrib="value" html attributes Regex attributeNameValueRegex = new Regex("(?<name>[\\w]*)=\"(?<value>[\\S\\s]*)\""); try { using (StreamReader streamReader = new StreamReader(new FileStream(@".\" + directory + path, FileMode.Open))) { var rawString = streamReader.ReadToEnd(); var strings = rawString.Split('\r', '\n'); foreach (var line in strings.Where(s => biisTagRegex.IsMatch(s))) { var regexMatch = biisTagRegex.Match(line); var controlType = regexMatch.Groups["controll"].Value; var content = regexMatch.Groups["content"].Value; var parameters = new Dictionary<string, string>(); var properties = regexMatch.Groups[1].Value.Split(' '); foreach (var property in properties) { regexMatch = attributeNameValueRegex.Match(property); var name = regexMatch.Groups["name"].Value; var value = regexMatch.Groups["value"].Value.Trim('\"', '\''); parameters.Add(name, value); } IBiisControl control; switch (controlType) { case "Button": control = new Button(parameters["value"]); if (parameters.ContainsKey("onclick")) control.HandlerFunction = parameters["onclick"]; break; case "Label": control = string.IsNullOrEmpty(content) ? new Label(parameters["value"]) : new Label(content); break; case "TextBox": control = new TextBox(content); string name = parameters["name"]; if (request.PostRequestParams.ContainsKey(name)) control.Value = request.PostRequestParams[name]; break; default: throw new Exception(); } if (parameters.ContainsKey("id")) control.Id = parameters["id"]; if (parameters.ContainsKey("name")) control.Name = parameters["name"]; if (parameters.ContainsKey("style")) control.Style = parameters["style"]; control.RawHtmlView = line; controls.Add(control.Name, control); } } } catch (Exception exc) { Console.WriteLine("Internal exception occured"); return null; } return controls; }
/// <summary> /// Parses request string and creating HttpRequest object /// </summary> /// <param name="content">Http request string</param> /// <returns>HttpRequest - representation of request</returns> public HttpRequest ParseRequest(string content) { Dictionary<string, string> properties = new Dictionary<string, string>(); HttpRequest request = new HttpRequest { PostRequestParams = new Dictionary<string, string>() }; string[] rows = content.Split('\r', '\n'); //Regex to find pairs name: value in http request header Regex requestRegex = new Regex("[\\s]*(?<name>[\\w-._]*):[\\s]*(?<value>[\\w\\S]*)[\\s]*"); //Regex to parse first line of request Regex firstLineRegex = new Regex("(?<verb>[A-Z]*)[\\s]*(?<path>[\\/\\.\\-\\w]*)[\\s\\S]*"); //Regex to parse post parameters Regex postParametersRegex = new Regex("(?<name>[\\w\\W]*)=(?<value>[\\S\\s]*)"); Match lineMatch; string propertyName; string propertyValue; try { //Parsing the first line to fing VERB and URI PATH var firstLineMatch = firstLineRegex.Match(rows[0]); request.Verb = firstLineMatch.Groups["verb"].Value; request.Path = firstLineMatch.Groups["path"].Value; //Parsing other lines to find other properties foreach (var line in rows.Where(line => requestRegex.IsMatch(line))) { lineMatch = requestRegex.Match(line); propertyName = lineMatch.Groups["name"].Value; propertyValue = lineMatch.Groups["value"].Value; properties.Add(propertyName, propertyValue); } if (properties.ContainsKey("Accept")) request.Accept = properties["Accept"]; if (properties.ContainsKey("Connection")) request.Connection = properties["Connection"]; if (properties.ContainsKey("Host")) request.Host = properties["Host"]; //Parsing POST request string if (string.Equals(request.Verb, "POST", StringComparison.CurrentCultureIgnoreCase)) { string[] postParmeters = rows[rows.Length - 1].Split('&'); foreach (string postParmeter in postParmeters) { lineMatch = postParametersRegex.Match(postParmeter); propertyName = lineMatch.Groups["name"].Value; propertyValue = lineMatch.Groups["value"].Value; request.PostRequestParams.Add(propertyName, propertyValue); } } } catch (Exception exc) { return null; } return request; }
/// <summary> /// Create http OK summary response for .biis page /// </summary> /// <param name="path">URI path</param> /// <param name="directory">Directory on disk</param> /// <param name="request">Http request</param> /// <returns>Summary http 200 OK response</returns> public string ResponseForDynamicPage(string path, string directory, HttpRequest request) { string htmlString; var controlsCollection = GetControlsCollection(path, directory, request); if (string.Equals(request.Verb, "POST")) controlsCollection = Compiler.ExecuteBiisCode(controlsCollection, path, directory); using (StreamReader streamReader = new StreamReader(new FileStream(@".\" + directory + path, FileMode.Open))) htmlString = streamReader.ReadToEnd(); htmlString = controlsCollection.Values.Aggregate(htmlString, (current, biisControl) => current.Replace(biisControl.RawHtmlView, biisControl.ToHtmlString())); return HttpHeader + htmlString; }
/// <summary> /// Checks whether requested page is static /// </summary> /// <param name="request">Http request</param> /// <returns></returns> public bool IsStaticPage(HttpRequest request) { return request.Path.Contains(".html"); }