Пример #1
0
        public async Task Interceptors_03()
        {
            var svc      = Common.Initialize();
            var executor = svc.GetService(typeof(IHttpExecutorAsync)) as IHttpExecutorAsync;

            var result = await executor.ExecuteAsync(
                new MagicRequest
            {
                URL     = "modules/interceptors/foo-args",
                Verb    = "get",
                Query   = new Dictionary <string, string>(),
                Headers = new Dictionary <string, string>(),
                Cookies = new Dictionary <string, string>(),
                Host    = "localhost",
                Scheme  = "http"
            });

            Assert.Equal(200, result.Result);
            Assert.Single(result.Headers);
            var hl = result.Content as string;

            Assert.NotNull(hl);
            var lambda = HyperlambdaParser.Parse(hl);

            // Notice, no [.arguments] node since no arguments were supplied to endpoint file.
            Assert.Equal(".interceptor-value", lambda.Children.First().Name);
            Assert.Equal("howdy", lambda.Children.First().Value);
            Assert.Equal(".endpoint-value", lambda.Children.Skip(1).First().Name);
            Assert.Equal("world", lambda.Children.Skip(1).First().Value);
        }
Пример #2
0
        public async Task PostEchoPartialArgumentList()
        {
            var svc      = Common.Initialize();
            var executor = svc.GetService(typeof(IHttpExecutorAsync)) as IHttpExecutorAsync;

            var input = HyperlambdaParser.Parse(@"
input1:foo
input2:int:5");

            var result = await executor.ExecuteAsync(
                new MagicRequest
            {
                URL     = "modules/echo",
                Verb    = "post",
                Query   = new Dictionary <string, string>(),
                Headers = new Dictionary <string, string>(),
                Cookies = new Dictionary <string, string>(),
                Host    = "localhost",
                Scheme  = "http",
                Payload = input
            });

            Assert.Equal(200, result.Result);
            Assert.Empty(result.Headers);
            var j = result.Content as JObject;

            Assert.NotNull(j);
            Assert.Equal(2, j.Count);
            Assert.Equal("foo", j["input1"].Value <string>());
            Assert.Equal(5, j["input2"].Value <int>());
        }
Пример #3
0
        static public Node Evaluate(string hl)
        {
            var lambda   = HyperlambdaParser.Parse(hl);
            var signaler = Initialize().GetService(typeof(ISignaler)) as ISignaler;

            signaler.Signal("eval", lambda);
            return(lambda);
        }
Пример #4
0
        static public Node Evaluate(string hl)
        {
            var signaler = Initialize();
            var lambda   = HyperlambdaParser.Parse(hl);

            signaler.Signal("eval", lambda);
            return(lambda);
        }
Пример #5
0
        static async public Task <Node> EvaluateAsync(string hl)
        {
            var signaler = Initialize();
            var lambda   = HyperlambdaParser.Parse(hl);
            await signaler.SignalAsync("eval", lambda);

            return(lambda);
        }
Пример #6
0
        static public async Task <Node> EvaluateAsync(string hl)
        {
            var services = Initialize();
            var lambda   = HyperlambdaParser.Parse(hl);
            var signaler = services.GetService(typeof(ISignaler)) as ISignaler;
            await signaler.SignalAsync("eval", lambda);

            return(lambda);
        }
Пример #7
0
        public async Task PutEcho()
        {
            var svc      = Common.Initialize();
            var executor = svc.GetService(typeof(IHttpExecutorAsync)) as IHttpExecutorAsync;

            var input = HyperlambdaParser.Parse(@"
input1:foo
input2:int:5
input3:bool:true
input4
   .
      arr1:bool:true
      arr2:57
      arr3:any-object
   .
      arr1:bool:false
      arr2:int:67
      arr3:guid:4c248403-23a7-4808-988c-1be59a4a90af
input5
   obj1:foo
   obj2:true");

            var result = await executor.ExecuteAsync(
                new MagicRequest
            {
                URL     = "modules/echo",
                Verb    = "put",
                Query   = new Dictionary <string, string>(),
                Headers = new Dictionary <string, string>(),
                Cookies = new Dictionary <string, string>(),
                Host    = "localhost",
                Scheme  = "http",
                Payload = input
            });

            Assert.Equal(200, result.Result);
            Assert.Empty(result.Headers);
            var j = result.Content as JObject;

            Assert.NotNull(j);
            Assert.Equal("foo", j["input1"].Value <string>());
            Assert.Equal(5, j["input2"].Value <int>());
            Assert.True(j["input3"].Value <bool>());
            Assert.NotNull(j["input4"].Value <JArray>());
            Assert.Equal(2, j["input4"].Value <JArray>().Count);
            Assert.True(j["input4"].Value <JArray>()[0]["arr1"].Value <bool>());
            Assert.Equal(57, j["input4"].Value <JArray>()[0]["arr2"].Value <int>());
            Assert.Equal("any-object", j["input4"].Value <JArray>()[0]["arr3"].Value <string>());
            Assert.False(j["input4"].Value <JArray>()[1]["arr1"].Value <bool>());
            Assert.Equal(67, j["input4"].Value <JArray>()[1]["arr2"].Value <int>());
            Assert.True(j["input4"].Value <JArray>()[1]["arr3"].Value <Guid>().ToString() != Guid.Empty.ToString());
            Assert.NotNull(j["input5"].Value <JObject>());
            Assert.Equal("foo", j["input5"].Value <JObject>()["obj1"].Value <string>());
            Assert.True(j["input5"].Value <JObject>()["obj2"].Value <bool>());
        }
Пример #8
0
        static public async Task <Node> EvaluateAsync(
            string hl,
            MockSmtpClient smtp,
            MockPop3Client pop3 = null)
        {
            var services = Initialize(smtp, pop3);
            var lambda   = HyperlambdaParser.Parse(hl);
            var signaler = services.GetService(typeof(ISignaler)) as ISignaler;
            await signaler.SignalAsync("eval", lambda);

            return(lambda);
        }
Пример #9
0
        static public Node Evaluate(
            string hl,
            MockSmtpClient smtp = null,
            MockPop3Client pop3 = null)
        {
            var services = Initialize(smtp, pop3);
            var lambda   = HyperlambdaParser.Parse(hl);
            var signaler = services.GetService(typeof(ISignaler)) as ISignaler;

            signaler.Signal("eval", lambda);
            return(lambda);
        }
Пример #10
0
        /*
         * Will recursively execute every single Hyperlambda file inside of
         * the specified folder.
         */
        static void ExecuteHyperlambdaFilesRecursively(IApplicationBuilder app, string folder)
        {
            // Creating our services.
            var fileService   = app.ApplicationServices.GetService <IFileService>();
            var folderService = app.ApplicationServices.GetService <IFolderService>();
            var signaler      = app.ApplicationServices.GetService <ISignaler>();

            // Startup folder, now executing all Hyperlambda files inside of it.
            foreach (var idxFile in fileService.ListFiles(folder, ".hl"))
            {
                var lambda = HyperlambdaParser.Parse(fileService.Load(idxFile));
                signaler.Signal("eval", lambda);
            }

            // Recursively checking sub folders.
            foreach (var idxFolder in folderService.ListFolders(folder))
            {
                ExecuteHyperlambdaFilesRecursively(app, idxFolder);
            }
        }
Пример #11
0
        /// <inheritdoc/>
        public async Task <MagicResponse> ExecuteAsync(MagicRequest request)
        {
            // Sanity checking invocation
            if (string.IsNullOrEmpty(request.URL))
            {
                return new MagicResponse {
                           Result = 404
                }
            }
            ;

            // Making sure we never resolve to anything outside of "modules/" and "system/" folder.
            if (!request.URL.StartsWith("modules/") && !request.URL.StartsWith("system/"))
            {
                return new MagicResponse {
                           Result = 401
                }
            }
            ;

            // Figuring out file to execute, and doing some basic sanity checking.
            var path = Utilities.GetEndpointFilePath(_rootResolver, request.URL, request.Verb);

            if (!await _fileService.ExistsAsync(path))
            {
                return new MagicResponse {
                           Result = 404
                }
            }
            ;

            // Creating our lambda object by loading Hyperlambda file.
            var lambda = HyperlambdaParser.Parse(await _fileService.LoadAsync(path));

            // Applying interceptors.
            lambda = await ApplyInterceptors(lambda, request.URL);

            // Attaching arguments.
            _argumentsHandler.Attach(lambda, request.Query, request.Payload);

            // Invoking method responsible for actually executing lambda object.
            return(await ExecuteAsync(lambda, request));
        }

        #region [ -- Private helper methods -- ]

        /*
         * Applies interceptors to specified Node/Lambda object.
         */
        async Task <Node> ApplyInterceptors(Node result, string url)
        {
            // Checking to see if interceptors exists recursively upwards in folder hierarchy.
            var splits = url.Split(new char [] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            // Stripping away last entity (filename) of invocation.
            var folders = splits.Take(splits.Length - 1);

            // Iterating as long as we have more entities in list of folders.
            while (true)
            {
                // Checking if "current-folder/interceptor.hl" file exists.
                var current = _rootResolver.AbsolutePath(string.Join("/", folders) + "/interceptor.hl");

                if (_fileService.Exists(current))
                {
                    result = await ApplyInterceptor(result, current);
                }

                // Checking if we're done, and at root folder, at which point we break while loop.
                if (!folders.Any())
                {
                    break; // We're done, no more interceptors!
                }
                // Traversing upwards in hierarchy to be able to nest interceptors upwards in hierarchy.
                folders = folders.Take(folders.Count() - 1);
            }

            // Returning result to caller.
            return(result);
        }

        /*
         * Applies the specified interceptor and returns the transformed Node/Lambda result.
         */
        async Task <Node> ApplyInterceptor(Node lambda, string interceptorFile)
        {
            // Getting interceptor lambda.
            var interceptNode = HyperlambdaParser.Parse(await _fileService.LoadAsync(interceptorFile));

            // Moving [.arguments] from endpoint lambda to the top of interceptor lambda if existing.
            var args = lambda
                       .Children
                       .Where(x =>
                              x.Name == ".arguments" ||
                              x.Name == ".description" ||
                              x.Name == ".type" ||
                              x.Name == "auth.ticket.verify" ||
                              x.Name.StartsWith("validators."));

            // Notice, reversing arguments nodes makes sure we apply arguments in order of appearance.
            foreach (var idx in args.Reverse().ToList())
            {
                interceptNode.Insert(0, idx); // Notice, will detach the argument from its original position!
            }

            // Moving endpoint Lambda to position before any [.interceptor] node found in interceptor lambda.
            foreach (var idxLambda in new Expression("**/.interceptor").Evaluate(interceptNode).ToList())
            {
                // Iterating through each node in current result and injecting before currently iterated [.lambda] node.
                foreach (var idx in lambda.Children)
                {
                    // This logic ensures we keep existing order without any fuzz.
                    // By cloning node we also support having multiple [.interceptor] nodes.
                    idxLambda.InsertBefore(idx.Clone());
                }

                // Removing currently iterated [.interceptor] node in interceptor lambda object.
                idxLambda.Parent.Remove(idxLambda);
            }

            // Returning interceptor Node/Lambda which is now the root of the execution Lambda object.
            return(interceptNode);
        }

        /*
         * Method responsible for actually executing lambda object after file has been loaded,
         * interceptors and arguments have been applied, and transforming result of invocation
         * to a MagicResponse.
         */
        async Task <MagicResponse> ExecuteAsync(Node lambda, MagicRequest request)
        {
            // Creating our result wrapper, wrapping whatever the endpoint wants to return to the client.
            var result   = new Node();
            var response = new MagicResponse();

            try
            {
                await _signaler.ScopeAsync("http.request", request, async() =>
                {
                    await _signaler.ScopeAsync("http.response", response, async() =>
                    {
                        await _signaler.ScopeAsync("slots.result", result, async() =>
                        {
                            await _signaler.SignalAsync("eval", lambda);
                        });
                    });
                });

                response.Content = GetReturnValue(response, result);
                return(response);
            }
            catch
            {
                if (result.Value is IDisposable disposable)
                {
                    disposable.Dispose();
                }
                if (response.Content is IDisposable disposable2 && !object.ReferenceEquals(response.Content, result.Value))
                {
                    disposable2.Dispose();
                }
                throw;
            }
        }

        /*
         * Creates a returned payload of some sort and returning to caller.
         */
        object GetReturnValue(MagicResponse httpResponse, Node lambda)
        {
            /*
             * An endpoint can return either a Node/Lambda hierarchy or a simple value.
             * First we check if endpoint returned a simple value, at which point we convert it to
             * a string. Notice, we're prioritising simple values, implying if return node has a
             * simple value, none of its children nodes will be returned.
             */
            if (lambda.Value != null)
            {
                // IDisposables (Streams e.g.) are automatically disposed by ASP.NET Core.
                if (lambda.Value is IDisposable || lambda.Value is byte[])
                {
                    return(lambda.Value);
                }

                return(lambda.Get <string>());
            }
            else if (lambda.Children.Any())
            {
                // Checking if we should return content as Hyperlambda.
                if (httpResponse.Headers.TryGetValue("Content-Type", out var val) && val == "application/x-hyperlambda")
                {
                    return(HyperlambdaGenerator.GetHyperlambda(lambda.Children));
                }

                // Defaulting to returning content as JSON by converting from Lambda to JSON.
                var convert = new Node();
                convert.AddRange(lambda.Children.ToList());
                _signaler.Signal(".lambda2json-raw", convert);
                return(convert.Value);
            }
            return(null); // No content
        }

        #endregion
    }
}