Exemplo n.º 1
0
        private async Task ProcessWithDiskCache(HttpContext context, string cacheKey, ImageJobInfo info)
        {
            var cacheResult = await diskCache.GetOrCreate(cacheKey, info.EstimatedFileExtension, async (stream) =>
            {
                if (info.HasParams)
                {
                    logger?.LogInformation("DiskCache Miss: Processing image {VirtualPath}{QueryString}", info.FinalVirtualPath, info);


                    var result = await info.ProcessUncached();
                    if (result.ResultBytes.Array == null)
                    {
                        throw new InvalidOperationException("Image job returned zero bytes.");
                    }
                    await stream.WriteAsync(result.ResultBytes.Array, result.ResultBytes.Offset,
                                            result.ResultBytes.Count,
                                            CancellationToken.None);
                    await stream.FlushAsync();
                }
                else
                {
                    logger?.LogInformation("DiskCache Miss: Proxying image {VirtualPath}", info.FinalVirtualPath);
                    await info.CopyPrimaryBlobToAsync(stream);
                }
            });

            if (cacheResult.Result == CacheQueryResult.Miss)
            {
                GlobalPerf.Singleton.IncrementCounter("diskcache_miss");
            }
            else if (cacheResult.Result == CacheQueryResult.Hit)
            {
                GlobalPerf.Singleton.IncrementCounter("diskcache_hit");
            }
            else if (cacheResult.Result == CacheQueryResult.Failed)
            {
                GlobalPerf.Singleton.IncrementCounter("diskcache_timeout");
            }

            // Note that using estimated file extension instead of parsing magic bytes will lead to incorrect content-type
            // values when the source file has a mismatched extension.

            if (cacheResult.Data != null)
            {
                if (cacheResult.Data.Length < 1)
                {
                    throw new InvalidOperationException("DiskCache returned cache entry with zero bytes");
                }
                SetCachingHeaders(context, cacheKey);
                await MagicBytes.ProxyToStream(cacheResult.Data, context.Response);
            }
            else
            {
                logger?.LogInformation("Serving {0}?{1} from disk cache {2}", info.FinalVirtualPath, info.CommandString, cacheResult.RelativePath);
                await ServeFileFromDisk(context, cacheResult.PhysicalPath, cacheKey);
            }
        }
Exemplo n.º 2
0
 private async Task ServeFileFromDisk(HttpContext context, string path, string etag)
 {
     await using var readStream = File.OpenRead(path);
     if (readStream.Length < 1)
     {
         throw new InvalidOperationException("DiskCache file entry has zero bytes");
     }
     SetCachingHeaders(context, etag);
     await MagicBytes.ProxyToStream(readStream, context.Response);
 }
Exemplo n.º 3
0
        private async Task ProcessWithStreamCache(HttpContext context, string cacheKey, ImageJobInfo info)
        {
            var keyBytes    = Encoding.UTF8.GetBytes(cacheKey);
            var typeName    = streamCache.GetType().Name;
            var cacheResult = await streamCache.GetOrCreateBytes(keyBytes, async (cancellationToken) =>
            {
                if (info.HasParams)
                {
                    logger?.LogDebug("{CacheName} miss: Processing image {VirtualPath}?{Querystring}", typeName, info.FinalVirtualPath, info.ToString());
                    var result = await info.ProcessUncached();
                    if (result.ResultBytes.Array == null)
                    {
                        throw new InvalidOperationException("Image job returned zero bytes.");
                    }
                    return(new Tuple <string, ArraySegment <byte> >(result.ContentType, result.ResultBytes));
                }

                logger?.LogDebug("{CacheName} miss: Proxying image {VirtualPath}", typeName, info.FinalVirtualPath);
                var bytes = await info.GetPrimaryBlobBytesAsync();
                return(new Tuple <string, ArraySegment <byte> >(null, bytes));
            }, CancellationToken.None, false);

            if (cacheResult.Status != null)
            {
                GlobalPerf.Singleton.IncrementCounter($"{typeName}_{cacheResult.Status}");
            }
            if (cacheResult.Data != null)
            {
                await using (cacheResult.Data)
                {
                    if (cacheResult.Data.Length < 1)
                    {
                        throw new InvalidOperationException($"{typeName} returned cache entry with zero bytes");
                    }
                    SetCachingHeaders(context, cacheKey);
                    await MagicBytes.ProxyToStream(cacheResult.Data, context.Response);
                }
                logger?.LogDebug("Serving from {CacheName} {VirtualPath}?{CommandString}", typeName, info.FinalVirtualPath, info.CommandString);
            }
            else
            {
                // TODO explore this failure path better
                throw new NullReferenceException("Caching failed: " + cacheResult.Status);
            }
        }
Exemplo n.º 4
0
        private async Task ProcessWithNoCache(HttpContext context, ImageJobInfo info)
        {
            // If we're not caching, we should always use the modified date from source blobs as part of the etag

            var betterCacheKey = await info.GetExactCacheKey();

            if (context.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var etag) && betterCacheKey == etag)
            {
                GlobalPerf.Singleton.IncrementCounter("etag_hit");
                context.Response.StatusCode    = StatusCodes.Status304NotModified;
                context.Response.ContentLength = 0;
                context.Response.ContentType   = null;
                return;
            }
            GlobalPerf.Singleton.IncrementCounter("etag_miss");
            if (info.HasParams)
            {
                logger?.LogInformation("Processing image {VirtualPath} with params {CommandString}", info.FinalVirtualPath, info.CommandString);
                GlobalPerf.Singleton.IncrementCounter("nocache_processed");
                var imageData = await info.ProcessUncached();

                var imageBytes  = imageData.ResultBytes;
                var contentType = imageData.ContentType;

                // write to stream
                context.Response.ContentType   = contentType;
                context.Response.ContentLength = imageBytes.Count;
                SetCachingHeaders(context, betterCacheKey);

                if (imageBytes.Array == null)
                {
                    throw new InvalidOperationException("Image job returned zero bytes.");
                }
                await context.Response.Body.WriteAsync(imageBytes.Array, imageBytes.Offset, imageBytes.Count);
            }
            else
            {
                logger?.LogInformation("Proxying image {VirtualPath} with params {CommandString}", info.FinalVirtualPath, info.CommandString);
                GlobalPerf.Singleton.IncrementCounter("nocache_proxied");
                await using var sourceStream = (await info.GetPrimaryBlob()).OpenRead();
                SetCachingHeaders(context, betterCacheKey);
                await MagicBytes.ProxyToStream(sourceStream, context.Response);
            }
        }