Exemplo n.º 1
0
        private static RequestFileCacheMetadata AddFileCacheEntry(string requestPath, string es5FilePath, string sourceChecksum)
        {
            RequestFileCacheMetadata rfc = new RequestFileCacheMetadata();

            rfc.Path          = requestPath;
            rfc.ES5Path       = es5FilePath;
            rfc.SourceETag    = sourceChecksum;
            rfc.ETag          = GetETagForES5File(sourceChecksum);
            rfc.ContentLength = new FileInfo(es5FilePath).Length.ToString();

            if (!_cachedFiles.ContainsKey(requestPath))
            {
                //If unable to add, that mean an other thread added the file. Returning the file from the other thread
                if (!_cachedFiles.TryAdd(requestPath, rfc))
                {
                    rfc = _cachedFiles.GetOrAdd(requestPath, rfc);
                }
            }
            else
            {
                rfc = _cachedFiles.AddOrUpdate(requestPath, rfc, (requestKeyPath, existingRFC) =>
                {
                    return(rfc);
                });
            }

            return(rfc);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Please call <see cref="HasES5FileInCacheByPath"/> and <see cref="HasES5FileInCacheWithChecksum"/> before calling this method, as
        /// theses method may populate the cache the first time.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static RequestFileCacheMetadata GetES5FileFromCache(string path)
        {
            if (_cachedFiles.ContainsKey(path))
            {
                RequestFileCacheMetadata resultValue = null;
                _cachedFiles.TryGetValue(path, out resultValue);

                //As we don't remove data from dictionary, this should be OK. Assuring we don't have any concurrency by using the previous method
                return(resultValue);
            }

            return(null);
        }
Exemplo n.º 3
0
        private async Task ManageES5Conversion(HttpContext context)
        {
            //If this return true here, this mean this is a subsequent call to a file
            //and that the file has already been cached in the internal dictionary
            //Otherwise we must try to seek the file hash of the current request and see
            //if it has been converted at least once in the app lifetime
            if (ES5CacheHelper.HasES5FileInCacheByPath(context.Request.Path))
            {
                var fileCache = ES5CacheHelper.GetES5FileFromCache(context.Request.Path);

                //Manage request specificity
                await HttpRequestManager.ManageRequest(context, fileCache.ES5Path, fileCache.ETag, fileCache.ContentLength);

                return;
            }

            //Here we are tricking the StaticFile handler by modifying the Body Stream type before it try to write in it.
            //Using a MemoryStream in order to be able to catch and modify the content afterward
            var originalResponseStream = context.Response.Body;

            using (var fakeResponseStream = new MemoryStream())
            {
                context.Response.Body = fakeResponseStream;

                //Awaiting StaticFile to fill the content
                await _next(context);

                //If the requested file return 304 status code, we should not try to cache / resolve this file
                //as StaticFileMiddleware does not return the data in this case
                //Same as if there is any other behavior that is not a success (not 200) we must retrieve and return the initial stream modified by the other context
                //without any alteration
                if (context.Response.StatusCode != 200)
                {
                    //Restoring the original response WriteOnly Stream
                    context.Response.Body = await CopyStreamAsync(fakeResponseStream, originalResponseStream);

                    return;
                }

                var response = await ExtractResponseAsync(context.Request, context.Response);

                RequestFileCacheMetadata _cacheMetadata = null;

                //From here we must see if we have a corresponding hash for this fetched resource in the cache store. Subsequent call will short-circuit at the top of this method because
                //the cache entry dictionary will be populated. If the data is not present we will have
                //to cache the file in disk
                if (ES5CacheHelper.HasES5FileInCacheWithChecksum(context.Request.Path, response.SourceCheckSum))
                {
                    _cacheMetadata = ES5CacheHelper.GetES5FileFromCache(context.Request.Path);
                }
                else
                {
                    //Convert to ES5 the current response
                    var fileContent = ES5Convert(response);

                    if (fileContent == null)
                    {
                        //If here that mean that conversion failed.
                        //We will take the original object but will add
                        //current content as ES5 even if not
                        fileContent            = response;
                        fileContent.ES5Content = fileContent.SourceContent;
                    }

                    _cacheMetadata = ES5CacheHelper.SetES5FileInCache(fileContent);
                }

                //As we have interverted the original Http Stream in our 'using' above, we
                //must restore it in order to make the thing work normally
                context.Response.Body = originalResponseStream;

                //Manage request specificity
                await HttpRequestManager.ManageRequest(context, _cacheMetadata.ES5Path, _cacheMetadata.ETag, _cacheMetadata.ContentLength);
            }
        }