public ImageflowMiddleware( RequestDelegate next, IWebHostEnvironment env, IEnumerable <ILogger <ImageflowMiddleware> > logger, IEnumerable <IMemoryCache> memoryCache, IEnumerable <IDistributedCache> distributedCache, IEnumerable <ISqliteCache> sqliteCaches, IEnumerable <IClassicDiskCache> diskCache, IEnumerable <IBlobProvider> blobProviders, ImageflowMiddlewareOptions options) { this.next = next; this.options = options; this.env = env; this.logger = logger.FirstOrDefault(); this.memoryCache = memoryCache.FirstOrDefault(); this.diskCache = diskCache.FirstOrDefault(); this.distributedCache = distributedCache.FirstOrDefault(); this.sqliteCache = sqliteCaches.FirstOrDefault(); var providers = blobProviders.ToList(); var mappedPaths = options.MappedPaths.ToList(); if (options.MapWebRoot) { if (this.env?.WebRootPath == null) { throw new InvalidOperationException("Cannot call MapWebRoot if env.WebRootPath is null"); } mappedPaths.Add(new PathMapping("/", this.env.WebRootPath)); } blobProvider = new BlobProvider(providers, mappedPaths); diagnosticsPage = new DiagnosticsPage(env, this.logger, this.memoryCache, this.distributedCache, this.diskCache, providers); }
public ImageflowMiddleware( RequestDelegate next, IWebHostEnvironment env, IEnumerable <ILogger <ImageflowMiddleware> > logger, IEnumerable <IClassicDiskCache> diskCaches, IEnumerable <IStreamCache> streamCaches, IEnumerable <IBlobProvider> blobProviders, ImageflowMiddlewareOptions options) { this.next = next; options.Licensing ??= new Licensing(LicenseManagerSingleton.GetOrCreateSingleton( "imageflow_", new[] { env.ContentRootPath, Path.GetTempPath() })); this.options = options; this.env = env; this.logger = logger.FirstOrDefault(); diskCache = diskCaches.FirstOrDefault(); var streamCacheArray = streamCaches.ToArray(); if (streamCacheArray.Count() > 1) { throw new InvalidOperationException("Only 1 IStreamCache instance can be registered at a time"); } streamCache = streamCacheArray.FirstOrDefault(); var providers = blobProviders.ToList(); var mappedPaths = options.MappedPaths.ToList(); if (options.MapWebRoot) { if (this.env?.WebRootPath == null) { throw new InvalidOperationException("Cannot call MapWebRoot if env.WebRootPath is null"); } mappedPaths.Add(new PathMapping("/", this.env.WebRootPath)); } //Determine the active cache backend var streamCacheEnabled = streamCache != null && options.AllowCaching; var diskCacheEnabled = this.diskCache != null && options.AllowDiskCaching; if (streamCacheEnabled) { options.ActiveCacheBackend = CacheBackend.StreamCache; } else if (diskCacheEnabled) { options.ActiveCacheBackend = CacheBackend.ClassicDiskCache; } else { options.ActiveCacheBackend = CacheBackend.NoCache; } options.Licensing.Initialize(this.options); blobProvider = new BlobProvider(providers, mappedPaths); diagnosticsPage = new DiagnosticsPage(options, env, this.logger, streamCache, this.diskCache, providers); licensePage = new LicensePage(options); globalInfoProvider = new GlobalInfoProvider(options, env, this.logger, streamCache, this.diskCache, providers); options.Licensing.FireHeartbeat(); GlobalPerf.Singleton.SetInfoProviders(new List <IInfoProvider>() { globalInfoProvider }); }
// ReSharper disable once UnusedMember.Global public async Task Invoke(HttpContext context) { // For instrumentation globalInfoProvider.CopyHttpContextInfo(context); var path = context.Request.Path; // Delegate to the diagnostics page if it is requested if (DiagnosticsPage.MatchesPath(path.Value)) { await diagnosticsPage.Invoke(context); return; } // Delegate to licenses page if requested if (licensePage.MatchesPath(path.Value)) { await licensePage.Invoke(context); return; } // Respond to /imageflow.ready if ("/imageflow.ready".Equals(path.Value, StringComparison.Ordinal)) { options.Licensing.FireHeartbeat(); using (new JobContext()) { await StringResponseNoCache(context, 200, "Imageflow.Server is ready to accept requests."); } return; } // Respond to /imageflow.health if ("/imageflow.health".Equals(path.Value, StringComparison.Ordinal)) { options.Licensing.FireHeartbeat(); await StringResponseNoCache(context, 200, "Imageflow.Server is healthy."); return; } // We only handle requests with an image extension or if we configured a path prefix for which to handle // extensionless requests if (!ImageJobInfo.ShouldHandleRequest(context, options)) { await next.Invoke(context); return; } options.Licensing.FireHeartbeat(); var imageJobInfo = new ImageJobInfo(context, options, blobProvider); if (!imageJobInfo.Authorized) { await NotAuthorized(context, imageJobInfo.AuthorizedMessage); return; } if (imageJobInfo.LicenseError) { if (options.EnforcementMethod == EnforceLicenseWith.Http422Error) { await StringResponseNoCache(context, 422, options.Licensing.InvalidLicenseMessage); return; } if (options.EnforcementMethod == EnforceLicenseWith.Http402Error) { await StringResponseNoCache(context, 402, options.Licensing.InvalidLicenseMessage); return; } } // If the file is definitely missing hand to the next middleware // Remote providers will fail late rather than make 2 requests if (!imageJobInfo.PrimaryBlobMayExist()) { await next.Invoke(context); return; } string cacheKey = null; var cachingPath = imageJobInfo.NeedsCaching() ? options.ActiveCacheBackend : CacheBackend.NoCache; if (cachingPath != CacheBackend.NoCache) { cacheKey = await imageJobInfo.GetFastCacheKey(); if (context.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var etag) && cacheKey == 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"); } try { switch (cachingPath) { case CacheBackend.ClassicDiskCache: await ProcessWithDiskCache(context, cacheKey, imageJobInfo); break; case CacheBackend.NoCache: await ProcessWithNoCache(context, imageJobInfo); break; case CacheBackend.StreamCache: await ProcessWithStreamCache(context, cacheKey, imageJobInfo); break; default: throw new ArgumentOutOfRangeException(); } GlobalPerf.Singleton.IncrementCounter("middleware_ok"); } catch (BlobMissingException e) { await NotFound(context, e); } catch (Exception e) { var errorName = e.GetType().Name; var errorCounter = "middleware_" + errorName; GlobalPerf.Singleton.IncrementCounter(errorCounter); GlobalPerf.Singleton.IncrementCounter("middleware_errors"); throw; } finally { // Increment counter for type of file served var imageExtension = PathHelpers.GetImageExtensionFromContentType(context.Response.ContentType); if (imageExtension != null) { GlobalPerf.Singleton.IncrementCounter("module_response_ext_" + imageExtension); } } }