/// <summary> /// Process method checks for presence of a session id and sequence /// number. If they do not exist then they are initialized in evidence. /// If they do exist in evidence then the sequence number is incremented /// and added back to the evidence. /// </summary> /// <param name="data"> /// The <see cref="IFlowData"/> instance to process. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if the supplied data instance is null /// </exception> protected override void ProcessInternal(IFlowData data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } var evidence = data.GetEvidence().AsDictionary(); // If the evidence does not contain a session id then create a new one. if (evidence.ContainsKey(Constants.EVIDENCE_SESSIONID) == false) { data.AddEvidence(Constants.EVIDENCE_SESSIONID, GetNewSessionId()); } // If the evidence does not have a sequence then add one. Otherwise // increment it. if (evidence.ContainsKey(Constants.EVIDENCE_SEQUENCE) == false) { data.AddEvidence(Constants.EVIDENCE_SEQUENCE, 1); } else if (evidence.TryGetValue(Constants.EVIDENCE_SEQUENCE, out object sequence)) { if (sequence is int result || (sequence is string seq && int.TryParse(seq, out result))) { data.AddEvidence(Constants.EVIDENCE_SEQUENCE, result + 1); } else { data.AddError(new Exception(Messages.MessageFailSequenceNumberParse), this); Logger.LogError(Messages.MessageFailSequenceNumberIncrement); } }
/// <summary> /// Process the math operation by parsing the text and computing the /// result. /// </summary> /// <param name="data">FlowData to add the result to</param> protected override void ProcessInternal(IFlowData data) { MathData elementData = (MathData)data.GetOrAdd( ElementDataKeyTyped, (f) => base.CreateElementData(f)); string operation = ((string)data.GetEvidence()[EvidenceKeys[0]]); if (operation != null) { // Parse the text representation of the mathematical operation. elementData.Operation = operation .Replace("plus", "+") .Replace("minus", "-") .Replace("divide", "/") .Replace("times", "*"); // Compute the value of the operation. elementData.Result = Convert.ToDouble( new DataTable().Compute(elementData.Operation, "")); } else { // Nothing provided, so just set zeros. elementData.Operation = "0"; elementData.Result = 0; } }
/// <summary> /// Generate the Content to send in the POST request. The evidence keys /// e.g. 'query.' and 'header.' have an order of precedence. These are /// added to the evidence in reverse order, if there is conflict then /// the queryData value is overwritten. /// /// 'query.' evidence should take precedence over all other evidence. /// If there are evidence keys other than 'query.' that conflict then /// this is unexpected so an error will be logged. /// </summary> /// <param name="data"></param> /// <returns>Evidence in a FormUrlEncodedContent object</returns> private FormUrlEncodedContent GetContent(IFlowData data) { var queryData = new Dictionary <string, string>(); queryData.Add("resource", _resourceKey); if (string.IsNullOrWhiteSpace(_licenseKey) == false) { queryData.Add("license", _licenseKey); } var evidence = data.GetEvidence().AsDictionary(); // Add evidence in reverse alphabetical order, excluding special keys. AddQueryData(queryData, evidence, evidence .Where(e => KeyHasPrefix(e, Core.Constants.EVIDENCE_QUERY_PREFIX) == false && KeyHasPrefix(e, Core.Constants.EVIDENCE_HTTPHEADER_PREFIX) == false && KeyHasPrefix(e, Core.Constants.EVIDENCE_COOKIE_PREFIX) == false) .OrderByDescending(e => e.Key)); // Add cookie evidence. AddQueryData(queryData, evidence, evidence .Where(e => KeyHasPrefix(e, Core.Constants.EVIDENCE_COOKIE_PREFIX))); // Add header evidence. AddQueryData(queryData, evidence, evidence .Where(e => KeyHasPrefix(e, Core.Constants.EVIDENCE_HTTPHEADER_PREFIX))); // Add query evidence. AddQueryData(queryData, evidence, evidence .Where(e => KeyHasPrefix(e, Core.Constants.EVIDENCE_QUERY_PREFIX))); var content = new FormUrlEncodedContent(queryData); return(content); }
/// <summary> /// Perform processing for this engine /// </summary> /// <param name="data"> /// The <see cref="IFlowData"/> instance containing data for the /// current request. /// </param> /// <param name="deviceData"> /// The <see cref="IDeviceDataHash"/> instance to populate with /// property values /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if a required parameter is null /// </exception> protected override void ProcessEngine(IFlowData data, IDeviceDataHash deviceData) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (deviceData == null) { throw new ArgumentNullException(nameof(deviceData)); } using (var relevantEvidence = new EvidenceDeviceDetectionSwig()) { foreach (var evidenceItem in data.GetEvidence().AsDictionary()) { if (EvidenceKeyFilter.Include(evidenceItem.Key)) { relevantEvidence.Add(new KeyValuePair <string, string>( evidenceItem.Key, evidenceItem.Value.ToString())); } } // The results object is disposed in the dispose method of the // DeviceDataHash object. #pragma warning disable CA2000 // Dispose objects before losing scope (deviceData as DeviceDataHash).SetResults(new ResultsSwigWrapper(_engine.process(relevantEvidence))); #pragma warning restore CA2000 // Dispose objects before losing scope } }
/// <summary> /// Generate any required parameters for the JSON request. /// Any query parameters from this request that were ingested by /// the Pipeline are added to the request URL by the JavaScript. /// </summary> /// <param name="data"></param> /// <returns></returns> protected virtual Dictionary <string, string> GetParameters(IFlowData data) { if (data == null) { throw new ArgumentException(Messages.ExceptionFlowDataIsNull); } var parameters = data .GetEvidence() .AsDictionary() .Where(e => e.Key.StartsWith(Core.Constants.EVIDENCE_QUERY_PREFIX, StringComparison.OrdinalIgnoreCase)) .Where(e => ExcludedParameters.Contains(e.Key) == false) .ToDictionary(k => { var dotPos = k.Key.IndexOf(Core.Constants.EVIDENCE_SEPERATOR, StringComparison.OrdinalIgnoreCase); return(WebUtility.UrlEncode(k.Key.Remove(0, dotPos + 1))); }, v => WebUtility.UrlEncode(v.Value.ToString())); // Serialise the parameters var paramsObject = JsonConvert.SerializeObject(parameters, Formatting.Indented); return(parameters); }
protected override void ProcessInternal(IFlowData data) { TestElementData elementData = data.GetOrAdd( ElementDataKeyTyped, (p) => new TestElementData(p)); int value = (int)data.GetEvidence()[EvidenceKeys[0]]; elementData.Result = value * 5; }
/// <summary> /// Process the client IP address by splitting the segments into an /// array /// </summary> /// <param name="data">FlowData to add the result to</param> protected override void ProcessInternal(IFlowData data) { SplitIpData elementData = (SplitIpData)data.GetOrAdd( ElementDataKeyTyped, (f) => base.CreateElementData(f)); string ip = ((string)data.GetEvidence()[EvidenceKeys[0]]); elementData.ClientIp = ip.Split('.', ':'); }
public void ValidateData(IFlowData data, bool validEvidence = true) { var elementData = data.GetFromElement(_engine); var dict = elementData.AsDictionary(); foreach (var property in _engine.Properties .Where(p => p.Available && // The JavascriptImageOptimiser property is deprecated. // It exists in the meta-data but is never populated // so we need to ignore it here. p.Name.Equals("JavascriptImageOptimiser", StringComparison.OrdinalIgnoreCase) == false)) { Assert.IsTrue(dict.ContainsKey(property.Name)); IAspectPropertyValue value = dict[property.Name] as IAspectPropertyValue; if (validEvidence) { Assert.IsTrue(value.HasValue); } else { if (property.Category.Equals("Device Metrics")) { Assert.IsTrue(value.HasValue); } else { Assert.IsFalse(value.HasValue); if (EvidenceContainsUserAgent(data) == false) { Assert.AreEqual("The evidence required to determine" + " this property was not supplied. The most" + " common evidence passed to this engine is" + " 'header.user-agent'.", value.NoValueMessage); } else { Assert.AreEqual("No matching profiles could be " + "found for the supplied evidence. A 'best " + "guess' can be returned by configuring more " + "lenient matching rules. See " + "https://51degrees.com/documentation/_device_detection__features__false_positive_control.html", value.NoValueMessage); } } } } Assert.IsTrue(string.IsNullOrEmpty(elementData.DeviceId.Value) == false); if (validEvidence == false) { Assert.AreEqual("0-0-0-0", elementData.DeviceId.Value); } var validKeys = data.GetEvidence().AsDictionary().Keys.Where( k => _engine.EvidenceKeyFilter.Include(k)).Count(); Assert.AreEqual(validKeys, elementData.UserAgents.Value.Count); }
/// <summary> /// Generate the Content to send in the POST request /// </summary> /// <param name="data"></param> /// <returns>Evidence in a FormUrlEncodedContent object</returns> private FormUrlEncodedContent GetContent(IFlowData data) { var evidence = data.GetEvidence().AsDictionary(); var queryData = new Dictionary<string, string>(); queryData.Add("resource", _resourceKey); if(string.IsNullOrWhiteSpace(_licenseKey) == false) { queryData.Add("license", _licenseKey); } foreach (var item in evidence) { var key = item.Key.Split(Core.Constants.EVIDENCE_SEPERATOR.ToCharArray()); queryData.Add(key[key.Length - 1], item.Value.ToString()); } var content = new FormUrlEncodedContent(queryData); return content; }
/// <summary> /// Process the flow data /// </summary> /// <param name="data"> /// The <see cref="IFlowData"/> /// </param> protected override void ProcessInternal(IFlowData data) { ListSplitterElementData elementData = data.GetOrAdd( ElementDataKeyTyped, (p) => new ListSplitterElementData(p)); // Get the source string string source = (string)data.GetEvidence()[EvidenceKeys[0]]; // Split the source string using the configured delimiter. var results = source .Split(_delimiters, StringSplitOptions.RemoveEmptyEntries) .ToList(); elementData.Result = new List <string>(); // Iterate through the resulting strings, checking if they are // over the max length. // If any string is too long then it is split into chunks of // max length. for (int i = 0; i < results.Count; i++) { var result = results[i]; while (result.Length > _maxLength) { // Take the first _maxLength characters and add them // to the element data result. elementData.Result.Add(result.Remove(_maxLength)); // Remove the first _maxLength characters from the // string and repeat. result = result.Substring(_maxLength); } // Add the string to the element data result. if (result.Length > 0) { elementData.Result.Add(result); } } }
private void SetUp(IFlowData data) { var host = Host; var protocol = Protocol; bool supportsPromises; if (string.IsNullOrEmpty(host)) { // Try and get the request host name so it can be used to request // the Json refresh in the JavaScript code. data.TryGetEvidence(Constants.EVIDENCE_HOST_KEY, out host); } if (string.IsNullOrEmpty(protocol)) { // Try and get the request protocol so it can be used to request // the JSON refresh in the JavaScript code. data.TryGetEvidence(Constants.EVIDENCE_PROTOCOL, out protocol); } // Couldn't get protocol from anywhere if (string.IsNullOrEmpty(protocol)) { protocol = Constants.DEFAULT_PROTOCOL; } // If device detection is in the Pipeline then we can check // if the client's browser supports promises. // This can be used to customize the JavaScript response. try { var promise = data.GetAs <IAspectPropertyValue <string> >("Promise"); supportsPromises = promise != null && promise.HasValue && promise.Value == "Full"; } catch (PipelineDataException) { supportsPromises = false; } catch (InvalidCastException) { supportsPromises = false; } catch (KeyNotFoundException) { supportsPromises = false; } // Get the JSON include to embed into the JavaScript include. string jsonObject = string.Empty; try { jsonObject = data.Get <IJsonBuilderElementData>().Json; } catch (KeyNotFoundException ex) { throw new PipelineConfigurationException( Messages.ExceptionJsonBuilderNotRun, ex); } // Generate any required parameters for the JSON request. List <string> parameters = new List <string>(); // Any query parameters from this request that were ingested by // the Pipeline are added to the request URL that will appear // in the JavaScript. var queryEvidence = data .GetEvidence() .AsDictionary() .Where(e => e.Key.StartsWith(Core.Constants.EVIDENCE_QUERY_PREFIX, StringComparison.OrdinalIgnoreCase)) .Select(k => { var dotPos = k.Key.IndexOf(Core.Constants.EVIDENCE_SEPERATOR, StringComparison.OrdinalIgnoreCase); return($"{WebUtility.UrlEncode(k.Key.Remove(0, dotPos + 1))}" + $"={WebUtility.UrlEncode(k.Value.ToString())}"); }); parameters.AddRange(queryEvidence); string queryParams = string.Join("&", parameters); string endpoint = Endpoint; Uri url = null; if (string.IsNullOrWhiteSpace(protocol) == false && string.IsNullOrWhiteSpace(host) == false && string.IsNullOrWhiteSpace(endpoint) == false) { var endpointHasSlash = endpoint[0] == '/'; var hostHasSlash = host[host.Length - 1] == '/'; // if there is no slash between host and endpoint then add one. if (endpointHasSlash == false && hostHasSlash == false) { endpoint = $"/{endpoint}"; } // if there are two slashes between host and endpoint then remove one. else if (endpointHasSlash == true && hostHasSlash == true) { endpoint = endpoint.Substring(1); } url = new Uri($"{protocol}://{host}{endpoint}" + (String.IsNullOrEmpty(queryParams) ? "" : $"?{queryParams}")); } // With the gathered resources, build a new JavaScriptResource. BuildJavaScript(data, jsonObject, supportsPromises, url); }