예제 #1
0
 public virtual void Save(string path, string message)
 {
     logger.Log("INFO", $"Saving message to {path}.");
     saveOrReadStorage.Save(path, message);
     cacheStorage.AddOrUpdate(path, message);
     logger.Log("INFO", $"Saved message to {path}.");
 }
예제 #2
0
        internal static void UpdateCachedResponse(CacheKey cacheKey,
                                                  HttpResponseMessage cachedResponse,
                                                  HttpResponseMessage serverResponse,
                                                  ICacheStore store)
        {
            TraceWriter.WriteLine("CachingHandler.UpdateCachedResponse - response: " + serverResponse.Headers,
                                  TraceLevel.Verbose);

            // update only if server had a cachecontrol.
            // TODO: merge CacheControl headers instead of replace
            if ((serverResponse.Headers.CacheControl != null) && !serverResponse.Headers.CacheControl.NoCache)
            // added to cover issue #139
            {
                TraceWriter.WriteLine(
                    "CachingHandler.UpdateCachedResponse - CacheControl: " + serverResponse.Headers.CacheControl,
                    TraceLevel.Verbose);
                cachedResponse.Headers.CacheControl = serverResponse.Headers.CacheControl;
            }
            else
            {
                TraceWriter.WriteLine(
                    "CachingHandler.UpdateCachedResponse - CacheControl missing from server. Applying sliding expiration. Date => " +
                    DateTimeOffset.UtcNow, TraceLevel.Verbose);
            }

            cachedResponse.Headers.Date = DateTimeOffset.UtcNow; // very important
            store.AddOrUpdate(cacheKey, cachedResponse);
        }
예제 #3
0
 internal static void UpdateCachedResponse(CacheKey cacheKey,
                                           HttpResponseMessage cachedResponse,
                                           HttpResponseMessage serverResponse,
                                           ICacheStore store)
 {
     // update only if server had a cachecontrol.
     // TODO: merge CacheControl headers instead of replace
     if (serverResponse.Headers.CacheControl != null)
     {
         cachedResponse.Headers.CacheControl = serverResponse.Headers.CacheControl;
         cachedResponse.Headers.Date         = DateTimeOffset.UtcNow; // very important
         store.AddOrUpdate(cacheKey, cachedResponse);
     }
 }
예제 #4
0
        internal static void UpdateCachedResponse(CacheKey cacheKey,
                                                  HttpResponseMessage cachedResponse,
                                                  HttpResponseMessage serverResponse,
                                                  ICacheStore store)
        {
            TraceWriter.WriteLine("CachingHandler.UpdateCachedResponse - response: " + serverResponse.Headers.ToString(), TraceLevel.Verbose);

            // update only if server had a cachecontrol.
            // TODO: merge CacheControl headers instead of replace
            if (serverResponse.Headers.CacheControl != null && (!serverResponse.Headers.CacheControl.NoCache)) // added to cover issue #139
            {
                TraceWriter.WriteLine("CachingHandler.UpdateCachedResponse - CacheControl: " + serverResponse.Headers.CacheControl.ToString(), TraceLevel.Verbose);
                cachedResponse.Headers.CacheControl = serverResponse.Headers.CacheControl;
                cachedResponse.Headers.Date         = DateTimeOffset.UtcNow; // very important
                store.AddOrUpdate(cacheKey, cachedResponse);
            }
        }
예제 #5
0
        internal static void UpdateCachedResponse(CacheKey cacheKey,
            HttpResponseMessage cachedResponse,
            HttpResponseMessage serverResponse,
            ICacheStore store)
        {
            TraceWriter.WriteLine("CachingHandler.UpdateCachedResponse - response: " + serverResponse.Headers.ToString(), TraceLevel.Verbose);
            
            // update only if server had a cachecontrol.
            // TODO: merge CacheControl headers instead of replace
	        if (serverResponse.Headers.CacheControl != null && (!serverResponse.Headers.CacheControl.NoCache)) // added to cover issue #139
	        {
		        TraceWriter.WriteLine("CachingHandler.UpdateCachedResponse - CacheControl: " + serverResponse.Headers.CacheControl.ToString(), TraceLevel.Verbose);
		        cachedResponse.Headers.CacheControl = serverResponse.Headers.CacheControl;
	        }
	        else
	        {
				TraceWriter.WriteLine("CachingHandler.UpdateCachedResponse - CacheControl missing from server. Applying sliding expiration. Date => " + DateTimeOffset.UtcNow, TraceLevel.Verbose);
			}
		
			cachedResponse.Headers.Date = DateTimeOffset.UtcNow; // very important
			store.AddOrUpdate(cacheKey, cachedResponse);
		}
예제 #6
0
        // TODO: this method is terribly long. Shorten
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var    cacheCowHeader = new CacheCowHeader();
            string uri            = request.RequestUri.ToString();

            TraceWriter.WriteLine("{0} - Starting SendAsync", TraceLevel.Verbose, request.RequestUri.ToString());


            // check if needs to be ignored
            if (_ignoreRequestRules(request))
            {
                return(base.SendAsync(request, cancellationToken)); // EXIT !! _________________
            }
            IEnumerable <string> varyHeaders;

            if (!VaryHeaderStore.TryGetValue(uri, out varyHeaders))
            {
                varyHeaders = DefaultVaryHeaders;
            }
            var cacheKey = new CacheKey(uri,
                                        request.Headers.Where(x => varyHeaders.Any(y => y.Equals(x.Key,
                                                                                                 StringComparison.CurrentCultureIgnoreCase)))
                                        .SelectMany(z => z.Value)
                                        );

            // get from cache and verify response
            HttpResponseMessage      cachedResponse;
            ResponseValidationResult validationResultForCachedResponse = ResponseValidationResult.NotExist;

            try
            {
                TraceWriter.WriteLine("{0} - Before TryGetValue", TraceLevel.Verbose, request.RequestUri.ToString());

                cacheCowHeader.DidNotExist = !_cacheStore.TryGetValue(cacheKey, out cachedResponse);
                TraceWriter.WriteLine("{0} - After TryGetValue: DidNotExist => {1}", TraceLevel.Verbose, request.RequestUri.ToString(), cacheCowHeader.DidNotExist);

                if (!cacheCowHeader.DidNotExist.Value) // so if it EXISTS in cache
                {
                    TraceWriter.WriteLine("{0} - Existed in the cache. CacheControl Headers => {1}", TraceLevel.Verbose, request.RequestUri.ToString(),
                                          cachedResponse.Headers.CacheControl.ToString());
                    cachedResponse.RequestMessage     = request;
                    validationResultForCachedResponse = ResponseValidator(cachedResponse);
                }

                TraceWriter.WriteLine("{0} - After ResponseValidator => {1}",
                                      TraceLevel.Verbose, request.RequestUri, validationResultForCachedResponse);


                // PUT validation
                if (request.Method == HttpMethod.Put && validationResultForCachedResponse.IsIn(
                        ResponseValidationResult.OK, ResponseValidationResult.MustRevalidate))
                {
                    DoPutValidation(request, cacheCowHeader, cachedResponse);
                    return(base.SendAsync(request, cancellationToken)); // EXIT !! _____________________________
                }

                // here onward is only GET only. See if cache OK and if it is then return
                if (validationResultForCachedResponse == ResponseValidationResult.OK)
                {
                    cacheCowHeader.RetrievedFromCache = true;
                    return(TaskHelpers.FromResult(cachedResponse.AddCacheCowHeader(cacheCowHeader))); // EXIT !! ____________________________
                }

                // if stale
                else if (validationResultForCachedResponse == ResponseValidationResult.Stale)
                {
                    cacheCowHeader.WasStale = true;
                    var isFreshOrStaleAcceptable = IsFreshOrStaleAcceptable(cachedResponse, request);
                    if (isFreshOrStaleAcceptable.HasValue && isFreshOrStaleAcceptable.Value) // similar to OK
                    {
                        // TODO: CONSUME AND RELEASE Response !!!
                        return(TaskHelpers.FromResult(cachedResponse.AddCacheCowHeader(cacheCowHeader)));
                        // EXIT !! ____________________________
                    }
                    else
                    {
                        validationResultForCachedResponse = ResponseValidationResult.MustRevalidate; // revalidate
                    }
                }

                // cache validation for GET
                else if (validationResultForCachedResponse == ResponseValidationResult.MustRevalidate)
                {
                    DoCacheValidationForGet(request, cacheCowHeader, cachedResponse);
                }
            }
            catch (Exception ex)
            {
                if (ExceptionHandler == null)
                {
                    throw;
                }
                else
                {
                    ExceptionHandler(ex);
                    Trace.TraceWarning("Exception was swallowed in CacheCow: " + ex.ToString());
                    return(base.SendAsync(request, cancellationToken));
                }
            }


            // _______________________________ RESPONSE only GET  ___________________________________________

            return(base.SendAsync(request, cancellationToken)
                   .ContinueWith(
                       tt =>
            {
                // HERE IS LATE FOR APPLYING EXCEPTION POLICY !!!

                var serverResponse = tt.Result;
                TraceWriter.WriteLine("{0} - After getting response",
                                      TraceLevel.Verbose, request.RequestUri.ToString());

                if (request.Method != HttpMethod.Get)     // only interested here if it is a GET - this line really never called - only GET gets here
                {
                    return serverResponse;
                }

                // in case of MustRevalidate with result 304
                if (validationResultForCachedResponse == ResponseValidationResult.MustRevalidate &&
                    serverResponse.StatusCode == HttpStatusCode.NotModified)
                {
                    TraceWriter.WriteLine("{0} - Got 304 from the server and ResponseValidationResult.MustRevalidate",
                                          TraceLevel.Verbose, request.RequestUri.ToString());

                    cachedResponse.RequestMessage = request;
                    cacheCowHeader.RetrievedFromCache = true;
                    TraceWriter.WriteLine("{0} - NotModified",
                                          TraceLevel.Verbose, request.RequestUri.ToString());

                    UpdateCachedResponse(cacheKey, cachedResponse, serverResponse, _cacheStore);
                    ConsumeAndDisposeResponse(serverResponse);
                    return cachedResponse.AddCacheCowHeader(cacheCowHeader);     // EXIT !! _______________
                }

                var validationResult = ResponseValidator(serverResponse);
                switch (validationResult)
                {
                case ResponseValidationResult.MustRevalidate:
                case ResponseValidationResult.OK:

                    TraceWriter.WriteLine("{0} - ResponseValidationResult.OK or MustRevalidate",
                                          TraceLevel.Verbose, request.RequestUri.ToString());


                    // prepare
                    ResponseStoragePreparationRules(serverResponse);

                    TraceWriter.WriteLine("{0} - Before AddOrUpdate", TraceLevel.Verbose, request.RequestUri.ToString());

                    // re-create cacheKey with real server accept

                    // if there is a vary header, store it
                    if (serverResponse.Headers.Vary != null)
                    {
                        varyHeaders = serverResponse.Headers.Vary.Select(x => x).ToArray();
                        IEnumerable <string> temp;
                        if (!VaryHeaderStore.TryGetValue(uri, out temp))
                        {
                            VaryHeaderStore.AddOrUpdate(uri, varyHeaders);
                        }
                    }

                    // create real cacheKey with correct Vary headers
                    cacheKey = new CacheKey(uri,
                                            request.Headers.Where(x => varyHeaders.Any(y => y.Equals(x.Key,
                                                                                                     StringComparison.CurrentCultureIgnoreCase)))
                                            .SelectMany(z => z.Value)
                                            );

                    // store the cache
                    _cacheStore.AddOrUpdate(cacheKey, serverResponse);

                    TraceWriter.WriteLine("{0} - After AddOrUpdate", TraceLevel.Verbose, request.RequestUri.ToString());


                    break;

                default:
                    TraceWriter.WriteLine("{0} - ResponseValidationResult. Other",
                                          TraceLevel.Verbose, request.RequestUri.ToString());

                    TraceWriter.WriteLine("{0} - Before TryRemove", TraceLevel.Verbose, request.RequestUri.ToString());
                    _cacheStore.TryRemove(cacheKey);
                    TraceWriter.WriteLine("{0} - After AddOrUpdate", TraceLevel.Verbose, request.RequestUri.ToString());

                    cacheCowHeader.NotCacheable = true;


                    break;
                }
                TraceWriter.WriteLine("{0} - Before returning response",
                                      TraceLevel.Verbose, request.RequestUri.ToString());

                return serverResponse.AddCacheCowHeader(cacheCowHeader);
            }));
        }
예제 #7
0
 internal static void UpdateCachedResponse(CacheKey cacheKey,
     HttpResponseMessage cachedResponse,
     HttpResponseMessage serverResponse,
     ICacheStore store)
 {
     // update only if server had a cachecontrol.
     // TODO: merge CacheControl headers instead of replace
     if (serverResponse.Headers.CacheControl != null)
     {
         cachedResponse.Headers.CacheControl = serverResponse.Headers.CacheControl;
         cachedResponse.Headers.Date = DateTimeOffset.UtcNow; // very important
         store.AddOrUpdate(cacheKey, cachedResponse);
     }
 }
예제 #8
0
        // TODO: this method is terribly long. Shorten
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var    cacheCowHeader = new CacheCowHeader();
            string uri            = request.RequestUri.ToString();

            TraceWriter.WriteLine("{0} - Starting", TraceLevel.Verbose, request.RequestUri.ToString());


            // check if needs to be ignored
            if (_ignoreRequestRules(request))
            {
                return(base.SendAsync(request, cancellationToken));                // EXIT !! _________________
            }
            IEnumerable <string> varyHeaders;

            if (!VaryHeaderStore.TryGetValue(uri, out varyHeaders))
            {
                varyHeaders = DefaultVaryHeaders;
            }
            var cacheKey = new CacheKey(uri,
                                        request.Headers.Where(x => varyHeaders.Any(y => y.Equals(x.Key,
                                                                                                 StringComparison.CurrentCultureIgnoreCase)))
                                        .SelectMany(z => z.Value)
                                        );

            // get from cache and verify response
            HttpResponseMessage      cachedResponse;
            ResponseValidationResult validationResultForCachedResponse = ResponseValidationResult.NotExist;

            TraceWriter.WriteLine("{0} - Before TryGetValue", TraceLevel.Verbose, request.RequestUri.ToString());

            cacheCowHeader.DidNotExist = !_cacheStore.TryGetValue(cacheKey, out cachedResponse);
            TraceWriter.WriteLine("{0} - After TryGetValue", TraceLevel.Verbose, request.RequestUri.ToString());

            if (!cacheCowHeader.DidNotExist.Value)             // so if it EXISTS in cache
            {
                cachedResponse.RequestMessage     = request;
                validationResultForCachedResponse = ResponseValidator(cachedResponse);
            }

            TraceWriter.WriteLine("{0} - After ResponseValidator {1}",
                                  TraceLevel.Verbose, request.RequestUri, validationResultForCachedResponse);


            // PUT validation
            if (request.Method == HttpMethod.Put && validationResultForCachedResponse.IsIn(
                    ResponseValidationResult.OK, ResponseValidationResult.MustRevalidate))
            {
                // add headers for a cache validation. First check ETag since is better
                if (UseConditionalPut)
                {
                    cacheCowHeader.CacheValidationApplied = true;
                    if (cachedResponse.Headers.ETag != null)
                    {
                        request.Headers.Add(HttpHeaderNames.IfMatch,
                                            cachedResponse.Headers.ETag.ToString());
                    }
                    else if (cachedResponse.Content.Headers.LastModified != null)
                    {
                        request.Headers.Add(HttpHeaderNames.IfUnmodifiedSince,
                                            cachedResponse.Content.Headers.LastModified.Value.ToString("r"));
                    }
                }
                return(base.SendAsync(request, cancellationToken));                // EXIT !! _____________________________
            }

            // here onward is only GET only. See if cache OK and if it is then return
            if (validationResultForCachedResponse == ResponseValidationResult.OK)
            {
                cacheCowHeader.RetrievedFromCache = true;
                return(TaskHelpers.FromResult(cachedResponse.AddCacheCowHeader(cacheCowHeader)));                // EXIT !! ____________________________
            }

            // if stale
            else if (validationResultForCachedResponse == ResponseValidationResult.Stale)
            {
                cacheCowHeader.WasStale = true;
                var isFreshOrStaleAcceptable = IsFreshOrStaleAcceptable(cachedResponse, request);
                if (isFreshOrStaleAcceptable.HasValue && isFreshOrStaleAcceptable.Value)             // similar to OK
                {
                    // TODO: CONSUME AND RELEASE Response !!!
                    return(TaskHelpers.FromResult(cachedResponse.AddCacheCowHeader(cacheCowHeader)));
                    // EXIT !! ____________________________
                }

                else
                {
                    validationResultForCachedResponse = ResponseValidationResult.MustRevalidate;             // revalidate
                }
            }

            // cache validation for GET
            else if (validationResultForCachedResponse == ResponseValidationResult.MustRevalidate)
            {
                cacheCowHeader.CacheValidationApplied = true;
                cacheCowHeader.WasStale = true;

                // add headers for a cache validation. First check ETag since is better
                if (cachedResponse.Headers.ETag != null)
                {
                    request.Headers.Add(HttpHeaderNames.IfNoneMatch,
                                        cachedResponse.Headers.ETag.ToString());
                }
                else if (cachedResponse.Content.Headers.LastModified != null)
                {
                    request.Headers.Add(HttpHeaderNames.IfModifiedSince,
                                        cachedResponse.Content.Headers.LastModified.Value.ToString("r"));
                }
            }

            // _______________________________ RESPONSE only GET  ___________________________________________

            return(base.SendAsync(request, cancellationToken)
                   .ContinueWith(
                       tt =>
            {
                var serverResponse = tt.Result;
                TraceWriter.WriteLine("{0} - After getting response",
                                      TraceLevel.Verbose, request.RequestUri.ToString());


                if (request.Method != HttpMethod.Get)                                 // only interested here if it is a GET - this line really never called - only GET gets here
                {
                    return serverResponse;
                }

                // in case of MustRevalidate with result 304
                if (validationResultForCachedResponse == ResponseValidationResult.MustRevalidate &&
                    serverResponse.StatusCode == HttpStatusCode.NotModified)
                {
                    cachedResponse.RequestMessage = request;
                    cacheCowHeader.RetrievedFromCache = true;
                    TraceWriter.WriteLine("{0} - NotModified",
                                          TraceLevel.Verbose, request.RequestUri.ToString());

                    ConsumeAndDisposeResponse(serverResponse);
                    return cachedResponse.AddCacheCowHeader(cacheCowHeader);                                     // EXIT !! _______________
                }

                var validationResult = ResponseValidator(serverResponse);
                switch (validationResult)
                {
                case ResponseValidationResult.MustRevalidate:
                case ResponseValidationResult.OK:

                    TraceWriter.WriteLine("{0} - ResponseValidationResult.OK or MustRevalidate",
                                          TraceLevel.Verbose, request.RequestUri.ToString());


                    // prepare
                    ResponseStoragePreparationRules(serverResponse);

                    TraceWriter.WriteLine("{0} - Before AddOrUpdate", TraceLevel.Verbose, request.RequestUri.ToString());

                    // store the cache
                    _cacheStore.AddOrUpdate(cacheKey, serverResponse);

                    TraceWriter.WriteLine("{0} - Before AddOrUpdate", TraceLevel.Verbose, request.RequestUri.ToString());

                    // if there is a vary header, store it
                    if (serverResponse.Headers.Vary != null)
                    {
                        VaryHeaderStore.AddOrUpdate(uri, serverResponse.Headers.Vary.Select(x => x).ToArray());
                    }
                    break;

                default:
                    TraceWriter.WriteLine("{0} - ResponseValidationResult. Other",
                                          TraceLevel.Verbose, request.RequestUri.ToString());

                    TraceWriter.WriteLine("{0} - Before TryRemove", TraceLevel.Verbose, request.RequestUri.ToString());
                    _cacheStore.TryRemove(cacheKey);
                    TraceWriter.WriteLine("{0} - After AddOrUpdate", TraceLevel.Verbose, request.RequestUri.ToString());

                    cacheCowHeader.NotCacheable = true;


                    break;
                }
                TraceWriter.WriteLine("{0} - Before returning response",
                                      TraceLevel.Verbose, request.RequestUri.ToString());

                return serverResponse.AddCacheCowHeader(cacheCowHeader);
            }
                       ));
        }