public async Task <T> GetOrAdd <T>(
            Uri uri,
            EsiExecutionContext executionContext,
            Func <Task <CacheResponse <T> > > valueFactory)
        {
            if (uri == null)
            {
                throw new ArgumentNullException(nameof(uri));
            }
            if (executionContext == null)
            {
                throw new ArgumentNullException(nameof(executionContext));
            }
            if (valueFactory == null)
            {
                throw new ArgumentNullException(nameof(valueFactory));
            }

            var(found, cached) = await TryGet <T>(uri, executionContext);

            if (found)
            {
                return(cached);
            }

            var response = await valueFactory();

            await Set(uri, executionContext, response);

            return(response.Value);
        }
Example #2
0
        public async Task Should_forward_headers()
        {
            HttpRequestMessage request = null;
            var client = new FakeHttpMessageHandler()
                         .Configure(new Uri("http://host/path"), r =>
            {
                request = r;
                return(new HttpResponseMessage());
            })
                         .ToClient();
            var loader = CreateHttpLoader(client);

            var executionContext = new EsiExecutionContext(
                new Dictionary <string, IReadOnlyCollection <string> >
            {
                ["Accept"]     = new[] { "text/html", "application/xhtml+xml" },
                ["Cookie"]     = new[] { "a=1; b=2" },
                ["Connection"] = new[] { "Keep-Alive" }
            },
                new Dictionary <string, IVariableValueResolver>());
            await loader.Get(new Uri("http://host/path"), executionContext);

            request.Headers.TryGetValues("Accept", out var acceptValues).Should().Be.True();
            acceptValues.Should().Have.SameSequenceAs("text/html", "application/xhtml+xml");
            request.Headers.TryGetValues("Cookie", out var cookieValues).Should().Be.True();
            cookieValues.Should().Have.SameSequenceAs("a=1; b=2");
            request.Headers.Contains("Connection").Should().Be.False();
        }
Example #3
0
        public static HttpRequestMessage Create(Uri uri, EsiExecutionContext executionContext)
        {
            if (uri == null)
            {
                throw new ArgumentNullException(nameof(uri));
            }
            if (executionContext == null)
            {
                throw new ArgumentNullException(nameof(executionContext));
            }

            var request = new HttpRequestMessage(HttpMethod.Get, uri);

            request.Headers.Add("X-Esi", "true");

            foreach (var header in executionContext.RequestHeaders.Where(h => !SkipHeaders.Contains(h.Key)))
            {
                if (!request.Headers.TryAddWithoutValidation(header.Key, header.Value))
                {
                    request.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }
            }

            return(request);
        }
Example #4
0
        public async Task <HttpResponseMessage> Handle(Uri uri, EsiExecutionContext executionContext, HttpLoadDelegate next)
        {
            _log("pipeline before");
            var response = await next(uri, executionContext);

            _log("pipeline after");
            return(response);
        }
Example #5
0
        private Task <HttpResponseMessage> ExecuteRequest(Uri uri, EsiExecutionContext executionContext)
        {
            var request = _httpRequestMessageFactory(uri, executionContext);

            var httpClient = _httpClientFactory(uri);

            return(httpClient.SendAsync(request));
        }
        public Task <IEnumerable <string> > Execute(EsiTextFragment fragment, EsiExecutionContext executionContext)
        {
            if (fragment == null)
            {
                throw new ArgumentNullException(nameof(fragment));
            }

            return(Task.FromResult <IEnumerable <string> >(new[] { fragment.Body }));
        }
Example #7
0
        private Task <HttpResponseMessage> Execute(Uri uri, EsiExecutionContext executionContext)
        {
            Task <HttpResponseMessage> Send(Uri u, EsiExecutionContext ec) => ExecuteRequest(uri, executionContext);

            return(_pipelines
                   .Aggregate(
                       (HttpLoadDelegate)Send,
                       (next, pipeline) => async(u, ec) => await pipeline.Handle(u, ec, next))(uri, executionContext));
        }
Example #8
0
        public async Task <IEnumerable <string> > Handle(
            EsiIncludeFragment fragment,
            EsiExecutionContext executionContext,
            ExecuteDelegate <EsiIncludeFragment> next)
        {
            var content = await next(fragment, executionContext);

            return(Wrap(content));
        }
        public async Task <IEnumerable <string> > Handle(
            EsiTextFragment fragment, EsiExecutionContext executionContext, ExecuteDelegate <EsiTextFragment> next)
        {
            var result = await next(new EsiTextFragment($"<{fragment.Body}>"), executionContext);

            var pre  = new[] { "pre" };
            var post = new[] { "post" };

            return(pre.Concat(result).Concat(post));
        }
        private async Task <CacheResponse <IEsiFragment> > RequestAndParse(
            Uri uri, EsiExecutionContext executionContext)
        {
            var response = await _httpLoader.Get(uri, executionContext);

            response.EnsureSuccessStatusCode();

            var content = await response.Content.ReadAsStringAsync();

            var fragment = _esiBodyParser.Parse(content);

            return(CacheResponse.Create(fragment, response.Headers.CacheControl, response.Headers.Vary.ToList()));
        }
Example #11
0
        public async Task Invoke(HttpContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Response.StatusCode == 304 || context.Request.Headers.ContainsKey("X-Esi"))
            {
                await _next(context);

                return;
            }

            var executionContext = new EsiExecutionContext(
                context.Request.Headers.ToDictionary(), context.Request.GetVariablesFromContext());
            var pageUri = context.Request.GetPageUri();

            var(found, cachedResponse) = await _cache.TryGet <FragmentPageResponse>(pageUri, executionContext);

            IEsiFragment fragment;

            if (found)
            {
                context.Response.CopyHeaders(cachedResponse.Headers);
                fragment = cachedResponse.Fragment;
            }
            else
            {
                var acceptEncoding = context.Request.Headers[HeaderNames.AcceptEncoding];
                context.Request.Headers[HeaderNames.AcceptEncoding] = StringValues.Empty;
                var body = await _next.TryIntercept(context);

                context.Request.Headers[HeaderNames.AcceptEncoding] = acceptEncoding;

                if (body == null)
                {
                    return;
                }

                fragment = _parser.Parse(body);

                await StoreFragmentInCache(context, pageUri, executionContext, fragment);
            }

            var content = await _executor.Execute(fragment, executionContext);

            await context.Response.WriteAllAsync(content);
        }
Example #12
0
        public static IEnumerable <string> Resolve(
            EsiExecutionContext executionContext, VariableString variableString)
        {
            if (executionContext == null)
            {
                throw new ArgumentNullException(nameof(executionContext));
            }
            if (variableString == null)
            {
                throw new ArgumentNullException(nameof(variableString));
            }

            return(variableString.Parts
                   .Select(o => ResolveStringPart(o, executionContext) ?? string.Empty));
        }
        public Task <IEnumerable <string> > Execute(EsiVarsFragment fragment, EsiExecutionContext executionContext)
        {
            if (fragment == null)
            {
                throw new ArgumentNullException(nameof(fragment));
            }
            if (executionContext == null)
            {
                throw new ArgumentNullException(nameof(executionContext));
            }

            var result = VariableStringResolver.Resolve(executionContext, fragment.Body);

            return(Task.FromResult(result));
        }
Example #14
0
        public async Task <IEnumerable <string> > Execute(EsiTryFragment fragment, EsiExecutionContext executionContext)
        {
            if (fragment == null)
            {
                throw new ArgumentNullException(nameof(fragment));
            }

            try
            {
                return(await _fragmentExecutor.Execute(fragment.AttemptFragment, executionContext));
            }
            catch (Exception ex)
            {
                _log.Error(() => "Error when executing attempt fragment.", ex);
                return(await _fragmentExecutor.Execute(fragment.ExceptFragment, executionContext));
            }
        }
Example #15
0
        private async Task StoreFragmentInCache(
            HttpContext context, Uri pageUri, EsiExecutionContext executionContext, IEsiFragment fragment)
        {
            CacheControlHeaderValue.TryParse(
                context.Response.Headers[HeaderNames.CacheControl], out var cacheControl);

            if (ShouldSetCache(context))
            {
                var headers      = context.Response.Headers.ToDictionary();
                var pageResponse = new FragmentPageResponse(fragment, headers);

                var vary          = context.Response.Headers[HeaderNames.Vary];
                var cacheResponse = CacheResponse.Create(pageResponse, cacheControl, vary);

                await _cache.Set(pageUri, executionContext, cacheResponse);
            }
        }
Example #16
0
        private static string ResolveStringPart(object obj, EsiExecutionContext executionContext)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            switch (obj)
            {
            case string s:
                return(s);

            case VariableExpression v:
                return(VariableResolver.ResolveValue(v, executionContext.Variables));

            default:
                throw new Exception($"Unknown part type '{obj.GetType().Name}'.");
            }
        }
        public async Task <IEnumerable <string> > Execute(
            EsiIncludeFragment fragment,
            EsiExecutionContext executionContext)
        {
            if (fragment == null)
            {
                throw new ArgumentNullException(nameof(fragment));
            }

            var rawUrl = string.Concat(VariableStringResolver.Resolve(executionContext, fragment.Url));
            var uri    = _uriParser(rawUrl);

            var remoteFragment = await _cache.GetOrAdd(
                uri,
                executionContext,
                () => RequestAndParse(uri, executionContext));

            return(await _fragmentExecutor.Execute(remoteFragment, executionContext));
        }
Example #18
0
        public void Parse_and_build(string input, string expected)
        {
            var variables = new Dictionary <string, IVariableValueResolver>
            {
                ["HTTP_HOST"]   = new SimpleVariableValueResolver(new Lazy <string>("example.com")),
                ["HTTP_COOKIE"] = new DictionaryVariableValueResolver(new Lazy <IReadOnlyDictionary <string, string> >(
                                                                          new Dictionary <string, string>
                {
                    ["showPricesWithVat"] = "true"
                }))
            };
            var executionContext = new EsiExecutionContext(
                new Dictionary <string, IReadOnlyCollection <string> >(), variables);

            var variableString = VariableStringParser.Parse(input);
            var actual         = string.Concat(VariableStringResolver.Resolve(executionContext, variableString));

            actual.Should().Be.EqualTo(expected);
        }
Example #19
0
        public async Task <HttpResponseMessage> Get(Uri uri, EsiExecutionContext executionContext)
        {
            if (uri == null)
            {
                throw new ArgumentNullException(nameof(uri));
            }

            try
            {
                var response = await Execute(uri, executionContext);

                response.EnsureSuccessStatusCode();
                return(response);
            }
            catch (Exception ex)
            {
                _log.Error(() => $"Error when loading '{uri}'.", ex);
                throw;
            }
        }
Example #20
0
        public Task <HttpResponseMessage> Handle(Uri uri, EsiExecutionContext executionContext, HttpLoadDelegate next)
        {
            var breakerPolicy = _breakerPolicies.GetOrAdd(_breakerKeyFactory(uri), _ => CreatePolicy());

            return(breakerPolicy.ExecuteAsync(() => next(uri, executionContext)));
        }
 public Task <IEnumerable <string> > Execute(EsiIgnoreFragment fragment, EsiExecutionContext executionContext)
 {
     return(Task.FromResult <IEnumerable <string> >(Array.Empty <string>()));
 }
        public async Task <IEnumerable <string> > Execute(EsiCompositeFragment fragment, EsiExecutionContext executionContext)
        {
            if (fragment == null)
            {
                throw new ArgumentNullException(nameof(fragment));
            }

            var tasks = fragment.Fragments
                        .Select(fragment1 => _fragmentExecutor.Execute(fragment1, executionContext));
            var results = await Task.WhenAll(tasks);

            return(results.SelectMany(s => s));
        }
        public async Task <IEnumerable <string> > Execute(EsiChooseFragment fragment, EsiExecutionContext executionContext)
        {
            if (fragment == null)
            {
                throw new ArgumentNullException(nameof(fragment));
            }
            if (executionContext == null)
            {
                throw new ArgumentNullException(nameof(executionContext));
            }

            var fragmentToShow = GetFirstSucceedingWhen(fragment.WhenFragments, executionContext.Variables) ?? fragment.OtherwiseFragment;

            return(await _fragmentExecutor.Execute(fragmentToShow, executionContext));
        }
 public Task <HttpResponseMessage> Handle(Uri uri, EsiExecutionContext executionContext, HttpLoadDelegate next)
 {
     return(_retryPolicy.ExecuteAsync(() => next(uri, executionContext)));
 }