/// <summary> /// Add a workbook and sheet reference to a prefix if they aren't provided yet /// </summary> /// <remarks>Qualify because (book,sheet,name) is a fully qualified name</remarks> public ParseTreeNode Qualify(ParseTreeNode reference) { // Check if this reference can be qualified if (!isPrefixableReference(reference)) { return(reference); } var referenced = reference.ChildNodes.First(node => !node.Is(GrammarNames.Prefix)); bool hasPrefix = reference.ChildNodes.Any(node => node.Is(GrammarNames.Prefix)); var prefix = reference.FirstOrNewChild(CustomParseTreeNode.NonTerminal(GrammarNames.Prefix)); PrefixInfo prefixinfo = null; if (hasPrefix) { prefixinfo = prefix.GetPrefixInfo(); } var file = prefix.FirstOrNewChild(CustomParseTreeNode.NonTerminal(GrammarNames.File, GrammarNames.TokenEnclosedInBrackets, $"[{DefinedIn.FileName}]")); var sheet = prefix.FirstOrNewChild(CustomParseTreeNode.Terminal(GrammarNames.TokenSheet, DefinedIn.Worksheet)); // Named ranges can be both workbook-level and sheet-level and need additional logic if (referenced.ChildNodes.First().Is(GrammarNames.NamedRange)) { var name = referenced.ChildNodes.First().ChildNodes.First().Token.ValueString; // If a sheet was already provided, either the file was provided or will correctly be filled by definition above if (!(prefixinfo != null && prefixinfo.HasSheet)) { bool isDefinedOnSheetLevel = NamedRanges.Contains(new NamedRangeDef(DefinedIn, name)); // If a file was provided but no sheet, it's a workbook-level definition // If a sheet-level name is not defined, either a workbook-level name is defined, // or it's not defined and we assume the Excel default of workbook-level if ((prefixinfo != null && prefixinfo.HasFile) || !isDefinedOnSheetLevel) { sheet = CustomParseTreeNode.Terminal(GrammarNames.TokenSheet, ""); } } } prefix = prefix.SetChildNodes(file, sheet); return(CustomParseTreeNode.From(reference).SetChildNodes(prefix, referenced)); }
public void ServeRequest(IHTTPContext context) { PrefixInfo c = Prefixes.Find(delegate(PrefixInfo item) { if (item.ExactMatch) { return(context.RequestPath.Equals(item.Prefix, PrefixComparison)); } else { return(context.RequestPath.StartsWith(item.Prefix, PrefixComparison)); } }); if (c.Handler != null) { c.Handler.ServeRequest(context); } else { context.Response.SendErrorResponse(404); } }
/// <summary> /// Verify that we can create HTTPS traffic manager rules for a /// site on the proxy port using a specific hostname and various /// path prefixes and then verify that that the traffic manager actually /// works by spinning up a [vegomatic] based service to accept the traffic. /// </summary> /// <param name="testName">Simple name (without spaces) used to ensure that URIs cached for different tests won't conflict.</param> /// <param name="proxyPort">The inbound proxy port.</param> /// <param name="network">The proxy network.</param> /// <param name="trafficManager">The traffic manager.</param> /// <param name="useCache">Optionally enable caching and verify.</param> /// <param name="serviceName">Optionally specifies the backend service name prefix (defaults to <b>vegomatic</b>).</param> /// <returns>The tracking <see cref="Task"/>.</returns> private async Task TestHttpsPrefix(string testName, int proxyPort, string network, TrafficManager trafficManager, bool useCache = false, string serviceName = "vegomatic") { // Append a GUID to the test name to ensure that we won't // conflict with what any previous test runs may have loaded // into the cache. testName += "-" + Guid.NewGuid().ToString("D"); // Verify that we can create an HTTP traffic manager rule for a // site on the proxy port using a specific hostname and then // verify that that the traffic manager actually works by spinning // up a [vegomatic] based service to accept the traffic. var manager = hive.GetReachableManager(); var hostname = testHostname; manager.Connect(); // Allow self-signed certificates. var handler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; using (var client = new TestHttpClient(disableConnectionReuse: true, handler: handler, disposeHandler: true)) { // Add the test certificate. hive.Certificate.Set("test-load-balancer", certificate); // Setup the client to query the [vegomatic] service through the // proxy without needing to configure a hive DNS entry. client.BaseAddress = new Uri($"https://{manager.PrivateAddress}:{proxyPort}/"); client.DefaultRequestHeaders.Host = hostname; // Create the traffic manager rules, one without a path prefix and // some others, some with intersecting prefixes so we can verify // that the longest prefixes are matched first. // // Each rule's backend will be routed to a service whose name // will be constructed from [testName] plus the prefix with the // slashes replaced with dashes. Each service will be configured // to return its name. var prefixes = new PrefixInfo[] { new PrefixInfo("/", $"{serviceName}"), new PrefixInfo("/foo/", $"{serviceName}-foo"), new PrefixInfo("/foo/bar/", $"{serviceName}-foo-bar"), new PrefixInfo("/foobar/", $"{serviceName}-foobar"), new PrefixInfo("/bar/", $"{serviceName}-bar") }; // Spin the services up first in parallel (for speed). Each of // these service will respond to requests with its service name. var tasks = new List <Task>(); foreach (var prefix in prefixes) { tasks.Add(Task.Run( () => { manager.SudoCommand($"docker service create --name {prefix.ServiceName} --network {network} --replicas 1 {vegomaticImage} test-server server-id={prefix.ServiceName}").EnsureSuccess(); })); } await NeonHelper.WaitAllAsync(tasks, TimeSpan.FromSeconds(30)); // Create the traffic manager rules. foreach (var prefix in prefixes) { var rule = new TrafficHttpRule() { Name = prefix.ServiceName, CheckExpect = "status 200", CheckSeconds = 1, }; if (useCache) { rule.Cache = new TrafficHttpCache() { Enabled = true }; } var frontend = new TrafficHttpFrontend() { Host = hostname, ProxyPort = proxyPort, CertName = "test-load-balancer" }; if (!string.IsNullOrEmpty(prefix.Path)) { frontend.PathPrefix = prefix.Path; } rule.Frontends.Add(frontend); rule.Backends.Add( new TrafficHttpBackend() { Server = prefix.ServiceName, Port = 80 }); trafficManager.SetRule(rule, deferUpdate: true); } trafficManager.Update(); // Wait for all of the services to report being ready. await NeonHelper.WaitForAsync( async() => { foreach (var prefix in prefixes) { try { var response = await client.GetAsync(prefix.Path); response.EnsureSuccessStatusCode(); } catch { return(false); } } return(true); }, timeout : TimeSpan.FromSeconds(60), pollTime : TimeSpan.FromSeconds(1)); // Give everything a chance to stablize. await Task.Delay(TimeSpan.FromSeconds(5)); // Now verify that prefix rules route to the correct backend service. foreach (var prefix in prefixes) { var response = await client.GetAsync($"{prefix.Path}{testName}?expires=60"); response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Assert.Equal(prefix.ServiceName, body.Trim()); if (useCache) { // Verify that the request routed through Varnish. Assert.True(ViaVarnish(response)); // This is the first request using the globally unique [testName] // so it should not be a cache hit. Assert.False(CacheHit(response)); } } // If caching is enabled, perform the requests again to ensure that // we see cache hits. if (useCache) { foreach (var prefix in prefixes) { // Request the item again and verify that it was a cache hit. var response = await client.GetAsync($"{prefix.Path}{testName}?expires=60"); response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Assert.Equal(prefix.ServiceName, body.Trim()); Assert.True(CacheHit(response)); } } } }
private static bool checkRowAndColumns(ParseTreeNode node, out PrefixInfo prefix, out bool columnEqual, out List <int> columns, out bool rowEqual, out List <int> rows) { var fargs = node.GetFunctionArguments().Select(arg => arg.SkipToRelevant()).ToList(); prefix = null; columnEqual = true; columns = new List <int>(); rowEqual = true; rows = new List <int>(); // Check if all arguments are single-cell references // And if all ar in the same column/row and prefix // Check first cell for initial values to compare if (!fargs[0].Is(GrammarNames.Reference)) { return(false); } if (!(fargs[0].ChildNodes[fargs[0].ChildNodes.Count == 1 ? 0 : 1]).Is(GrammarNames.Cell)) { return(false); } prefix = (fargs[0].ChildNodes.Count == 1 ? null : fargs[0].ChildNodes[0])?.GetPrefixInfo(); var loc = new Location((fargs[0].ChildNodes[fargs[0].ChildNodes.Count == 1 ? 0 : 1]).Print()); var column = loc.Column1; var row = loc.Row1; foreach (var refnode in fargs) { if (!refnode.Is(GrammarNames.Reference)) { return(false); } var index = refnode.ChildNodes.Count == 1 ? 0 : 1; // Check if it is a cell if (!refnode.ChildNodes[index].Is(GrammarNames.Cell)) { return(false); } // Check if all prefixes are equal if (index == 0 && prefix != null) { return(false); } if (index == 1 && !refnode.ChildNodes[0].GetPrefixInfo().Equals(prefix)) { return(false); } loc = new Location(refnode.ChildNodes[index].Print()); // Add rows/columns to the list and check if they are equal if (columnEqual && column != loc.Column1) { columnEqual = false; } if (rowEqual && row != loc.Row1) { rowEqual = false; } if (!columnEqual && !rowEqual) { return(false); } rows.Add(loc.Row1); columns.Add(loc.Column1); } return(true); }
private void AddPrefix(PrefixInfo item) { Prefixes.Add(item); Prefixes.Sort(delegate(PrefixInfo a, PrefixInfo b) { return(-String.CompareOrdinal(a.Prefix, b.Prefix)); }); }
/// <summary> /// Create unit abbreviations for a prefix unit, given a unit and the prefix. /// The unit abbreviations are either prefixed with the SI prefix or an explicitly configured abbreviation via /// <see cref="Localization.AbbreviationsForPrefixes" />. /// </summary> private static Localization[] GetLocalizationForPrefixUnit(IEnumerable <Localization> localizations, PrefixInfo prefixInfo) { return(localizations.Select(loc => { if (loc.TryGetAbbreviationsForPrefix(prefixInfo.Prefix, out string[] unitAbbreviationsForPrefix)) { return new Localization { Culture = loc.Culture, Abbreviations = unitAbbreviationsForPrefix }; } // No prefix unit abbreviations are specified, so fall back to prepending the default SI prefix to each unit abbreviation: // kilo ("k") + meter ("m") => kilometer ("km") var prefix = prefixInfo.GetPrefixForCultureOrSiPrefix(loc.Culture); unitAbbreviationsForPrefix = loc.Abbreviations.Select(unitAbbreviation => $"{prefix}{unitAbbreviation}").ToArray(); return new Localization { Culture = loc.Culture, Abbreviations = unitAbbreviationsForPrefix }; }).ToArray());