Ejemplo n.º 1
0
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            using var act = source.StartActivity("cache");
            act?.SetParentId(Tracer.CurrentSpan.Context.TraceId, Tracer.CurrentSpan.Context.SpanId);
            act?.SetTag("http.url", string.Concat(request.RequestUri.Scheme
                                                  , "://"
                                                  , request.RequestUri.Authority
                                                  , request.RequestUri.PathAndQuery
                                                  , request.RequestUri.Fragment)
                        );
            act?.SetTag("http.method", $"HTTP {request.Method}");

            var isCachable     = request.Method == HttpMethod.Get;
            var cacheKey       = CacheKey(request);
            var cachedResponse = cache[cacheKey] as CachedHttpResponse;

            act?.SetTag("http.cache.found", isCachable && cachedResponse != null);

            if (isCachable && cachedResponse != null)
            {
                // Houston, we have a cache hit!
                //
                // Normally a cache would also take into account the vary-headers to make sure the request is similair. For
                // now we don't care about this.
                if (cachedResponse.Headers.TryGetValue("ETag", out IList <string> etag))
                {
                    request.Headers.IfNoneMatch.ParseAdd(etag.Single());
                    act?.SetTag("etag", etag.Single());
                }
                if (cachedResponse.Headers.TryGetValue("Last-Modified", out IList <string> lastModified))
                {
                    request.Headers.IfModifiedSince = DateTimeOffset.Parse(lastModified.Single());
                    act?.SetTag("if-modified-since", lastModified.Single());
                }
            }

            var response = await base.SendAsync(request, cancellationToken);

            act?.SetTag("http.status_code", response.StatusCode);

            if (isCachable && cachedResponse != null && response.StatusCode == HttpStatusCode.NotModified)
            {
                act?.SetTag("http.cache.hit", true);
                return(cachedResponse.ToHttpResponse(response));
            }

            if (response.IsSuccessStatusCode && isCachable)
            {
                act?.SetTag("http.cache.miss", true);
                cachedResponse = await CachedHttpResponse.From(request, response);

                cache[cacheKey] = cachedResponse;

                // Creating the cache entry requires us to read the content stream. Since this is network stream and is
                // only meant to be read once, we have to reconstruct a http response from the cache entry.
                return(cachedResponse.ToHttpResponse(response));
            }

            return(response);
        }
Ejemplo n.º 2
0
            public async static Task <CachedHttpResponse> From(HttpRequestMessage request, HttpResponseMessage response)
            {
                var cached = new CachedHttpResponse
                {
                    RequestUri     = request.RequestUri
                    , Method       = request.Method.ToString()
                    , StatusCode   = response.StatusCode
                    , ReasonPhrase = response.ReasonPhrase
                };

                if (response.Content != null)
                {
                    using var ms = new MemoryStream();
                    await response.Content.CopyToAsync(ms);

                    ms.Position = 0;

                    using var sr   = new StreamContent(ms);
                    cached.Content = await sr.ReadAsByteArrayAsync();

                    ms.Seek(0, SeekOrigin.Begin);
                }

                foreach (var header in response.Headers)
                {
                    cached.Headers.TryAdd(header.Key, header.Value.ToList());
                }

                foreach (var header in response.Content?.Headers)
                {
                    cached.ContentHeaders.TryAdd(header.Key, header.Value.ToList());
                }

                return(cached);
            }