Ejemplo n.º 1
0
        public static void Merge(this IResponseMetadata metadataA, IResponseMetadata metadataB, bool useGreater = true)
        {
            metadataA.Date         = metadataA.Date.GetValue(metadataB.Date, useGreater);
            metadataA.LastModified = metadataA.LastModified.GetValue(metadataB.LastModified, useGreater);
            metadataA.Expiration   = metadataA.Expiration.GetValue(metadataB.Expiration, useGreater);

            if (metadataB.ShouldRevalidate)
            {
                metadataA.ShouldRevalidate = metadataB.ShouldRevalidate;
            }

            if (metadataB.ETag != null)
            {
                metadataA.ETag = (metadataA.ETag ?? string.Empty) + metadataB.ETag;
            }

            foreach (var header in metadataB.VaryHeaders.Where(header => !metadataA.VaryHeaders.Contains(header)))
            {
                metadataA.VaryHeaders.Add(header);
            }

            foreach (var uri in metadataB.DependentUris.Where(uri => !metadataA.DependentUris.Contains(uri)))
            {
                metadataA.DependentUris.Add(uri);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the request ID for logging.
        /// </summary>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="response">The response.</param>
        /// <param name="exception">The exception, if available.</param>
        /// <returns>The request ID.</returns>
        public string GetRequestId(Metadata responseHeaders, object response,
                                   RpcException exception)
        {
            string requestId = new AdsResponseMetadata(responseHeaders).RequestId;

            // For streaming calls, the trailing response headers are returned only after
            // the entire stream is read, whereas we write summary logs each time we retrieve
            // a response object from the stream. As a result, the requestId in summary logs
            // appear blank in all except the last entry. As a fix, we read the request Id
            // from the stream response object as a fallback.
            if (string.IsNullOrEmpty(requestId))
            {
                IResponseMetadata responseMetadata = response as IResponseMetadata;
                if (responseMetadata != null)
                {
                    requestId = responseMetadata.RequestId;
                }
            }
            if (string.IsNullOrEmpty(requestId))
            {
                AdsBaseException adsException = exception as AdsBaseException;
                if (adsException != null)
                {
                    requestId = adsException.RequestId;
                }
            }
            return(requestId);
        }
Ejemplo n.º 3
0
        public static IResponse <Target> MapMetadata <Target>(IResponseMetadata source) where Target : class
        {
            var target = new Response <Target>();

            target.Errors   = source.Errors;
            target.Messages = source.Messages;
            return(target);
        }
Ejemplo n.º 4
0
        public static bool AllowStale(HttpRequestMessage request, IResponseMetadata responseMetadata)
        {
            //This is almost verbatim from the CacheCow HttpCallCacheHandler's  IsFreshOrStaleAcceptable

            if (responseMetadata == null)
            {
                throw new ArgumentException(SR.CacheContextResponseInfoRequiredError, nameof(responseMetadata));
            }

            if (request == null)
            {
                throw new ArgumentException(SR.CacheContextRequestMessageRequiredError, nameof(request));
            }

            if (!responseMetadata.HasContent)
            {
                return(false);
            }

            if (responseMetadata.Expiration < DateTimeOffset.UtcNow)
            {
                return(false);
            }

            var responseDate = responseMetadata.LastModified ?? responseMetadata.Date;
            var staleness    = DateTimeOffset.UtcNow - responseDate;

            if (request.Headers.CacheControl == null)
            {
                return(staleness < TimeSpan.Zero);
            }

            if (request.Headers.CacheControl.MinFresh.HasValue)
            {
                return(-staleness > request.Headers.CacheControl.MinFresh.Value); // staleness is negative if still fresh
            }
            if (request.Headers.CacheControl.MaxStale)                            // stale acceptable
            {
                return(true);
            }

            if (request.Headers.CacheControl.MaxStaleLimit.HasValue)
            {
                return(staleness < request.Headers.CacheControl.MaxStaleLimit.Value);
            }

            if (request.Headers.CacheControl.MaxAge.HasValue)
            {
                return(responseDate.Add(request.Headers.CacheControl.MaxAge.Value) > DateTimeOffset.Now);
            }

            return(false);
        }
Ejemplo n.º 5
0
        public static ResponseValidationResult ValidateResponse(IResponseMetadata responseMetadata, ISet <HttpStatusCode> cacheableHttpStatusCodes)
        {
            //This is almost verbatim from the CacheCow HttpCacheHandler's ResponseValidator func

            // 13.4
            //Unless specifically constrained by a cache-control (section 14.9) directive, a caching system MAY always store
            // a successful response (see section 13.8) as a cache entry, MAY return it without validation if it
            // is fresh, and MAY return it after successful validation. If there is neither a cache validator nor an
            // explicit expiration time associated with a response, we do not expect it to be cached, but certain caches MAY violate this expectation
            // (for example, when little or no network connectivity is available).

            // 14.9.1
            // If the no-cache directive does not specify a field-name, then a cache MUST NOT use the response to satisfy a subsequent request without
            // successful revalidation with the origin server. This allows an origin server to prevent caching
            // even by caches that have been configured to return stale responses to client requests.
            //If the no-cache directive does specify one or more field-names, then a cache MAY use the response
            // to satisfy a subsequent request, subject to any other restrictions on caching. However, the specified
            // field-name(s) MUST NOT be sent in the response to a subsequent request without successful revalidation
            // with the origin server. This allows an origin server to prevent the re-use of certain header fields in a metadata, while still allowing caching of the rest of the response.

            if (!cacheableHttpStatusCodes.Contains(responseMetadata.StatusCode))
            {
                return(ResponseValidationResult.NotCacheable);
            }

            if (responseMetadata.NoStore)
            {
                return(ResponseValidationResult.NotCacheable);
            }

            if (!responseMetadata.HasContent)
            {
                return(ResponseValidationResult.NotCacheable);
            }

            if (!responseMetadata.Expiration.HasValue)
            {
                return(ResponseValidationResult.NotCacheable);
            }

            if (responseMetadata.NoCache)
            {
                return(ResponseValidationResult.MustRevalidate);
            }

            if (responseMetadata.Expiration < DateTimeOffset.UtcNow)
            {
                return(responseMetadata.ShouldRevalidate ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale);
            }

            return(ResponseValidationResult.OK);
        }
Ejemplo n.º 6
0
        private static IEnumerable <Uri> GetDependentUris(IResponseMetadata metadata, object result, IEnumerable <Uri> dependentUris)
        {
            var uris = (dependentUris ?? Enumerable.Empty <Uri>()).Concat(metadata.DependentUris);

            var cacheableResult = result as ICacheableHttpResult;

            if (cacheableResult?.DependentUris != null)
            {
                uris = uris.Concat(cacheableResult.DependentUris);
            }

            return(uris.Normalize());
        }
Ejemplo n.º 7
0
        public static bool ShouldRevalidate(HttpRequestMessage request, IResponseMetadata responseMetadata, ISet <HttpMethod> cacheableHttpMethods)
        {
            if (request == null)
            {
                return(false);
            }

            if (!cacheableHttpMethods.Contains(request.Method))
            {
                return(false);
            }

            return(responseMetadata != null && responseMetadata.StatusCode == HttpStatusCode.NotModified);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="AdsResponseMetadata"/> class.
 /// </summary>
 /// <param name="metadata">The metadata.</param>
 public AdsResponseMetadata(IResponseMetadata metadata) : base()
 {
     RequestId = metadata?.RequestId;
 }
Ejemplo n.º 9
0
 public CacheEntry(IResponseMetadata metadata)
 {
     Metadata = metadata;
 }
Ejemplo n.º 10
0
 public CacheEntry(object value, IResponseMetadata metadata)
     : this(metadata)
 {
     Value = value;
 }
Ejemplo n.º 11
0
 /// <summary>
 /// Called when a response metadata is received.
 /// </summary>
 /// <param name="responseMetadata">The response metadata.</param>
 internal void OnResponseMetadataReceived(IResponseMetadata responseMetadata)
 {
     Client?.OnResponseMetadataReceived?.Invoke(this, responseMetadata);
 }