예제 #1
0
        /// <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));
        }
예제 #2
0
        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);
            }
        }
예제 #3
0
        /// <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);
        }
예제 #5
0
 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());