/// <summary> /// Returns an IVirtualFileAsync instance if the specified file can be provided by an async provider /// </summary> /// <param name="virtualPath"></param> /// <param name="queryString"></param> /// <returns></returns> public async Task <IVirtualFileAsync> GetFileAsync(string virtualPath, NameValueCollection queryString) { IVirtualFileAsync f = null; foreach (IVirtualImageProviderAsync p in c.Plugins.GetAll <IVirtualImageProviderAsync>()) { if (await p.FileExistsAsync(virtualPath, queryString)) { f = await p.GetFileAsync(virtualPath, queryString); break; } } if (f == null) { return(null); } try { //Now we have a reference to the real virtual file, let's see if it is source-cached. IVirtualFileAsync cached = null; foreach (IVirtualFileCacheAsync p in c.Plugins.GetAll <IVirtualFileCacheAsync>()) { cached = await p.GetFileIfCachedAsync(virtualPath, queryString, f); if (cached != null) { return(cached); } } }catch (FileNotFoundException) { //IVirtualFileCache instances will .Open() and read the original IVirtualFile instance. return(null); } return(f); }
protected async Task CheckRequest_PostAuthorizeRequest_Async(object sender, EventArgs e) { //Skip requests if the Request object isn't populated HttpApplication app = sender as HttpApplication; if (app == null || app.Context == null || app.Context.Request == null) { return; } var ra = new HttpModuleRequestAssistant(app.Context, conf, this); var result = ra.PostAuthorize(); if (result == HttpModuleRequestAssistant.PostAuthorizeResult.UnrelatedFileType) { return; //Exit early, not our scene } if (result == HttpModuleRequestAssistant.PostAuthorizeResult.AccessDenied403) { ra.FireAccessDenied(); throw new ImageProcessingException(403, "Access denied", "Access denied"); } if (result == HttpModuleRequestAssistant.PostAuthorizeResult.Complete) { //Does the file exist physically? (false if VppUsage=always or file is missing) bool existsPhysically = (conf.VppUsage != VppUsageOption.Always); if (existsPhysically) { existsPhysically = File.Exists(ra.RewrittenMappedPath); } //If not present physically (and VppUsage!=never), try to get the virtual file. Null indicates a missing file IVirtualFileAsync vf = null; if (conf.VppUsage != VppUsageOption.Never && !existsPhysically) { vf = await conf.GetFileAsync(ra.RewrittenVirtualPath, ra.RewrittenQuery); } //Only process files that exist if (!existsPhysically && vf == null) { ra.FireMissing(); return; } try { await HandleRequest(app.Context, ra, vf); //Catch not found exceptions ra.FirePostAuthorizeSuccess(); } catch (System.IO.FileNotFoundException notFound) { //Some VPPs are optimistic, or could be a race condition if (notFound.Message.Contains(" assembly ")) { throw; //If an assembly is missing, it should be a 500, not a 404 } ra.FireMissing(); throw new ImageMissingException("The specified resource could not be located", "File not found", notFound); } catch (System.IO.DirectoryNotFoundException notFound) { ra.FireMissing(); throw new ImageMissingException("The specified resource could not be located", "File not found", notFound); } catch (Exception ex) { ra.FirePostAuthorizeRequestException(ex); throw; } } }
/// <summary> /// Generates the resized image to disk (if needed), then rewrites the request to that location. /// Perform 404 checking before calling this method. Assumes file exists. /// Called during PostAuthorizeRequest /// </summary> /// <param name="context"></param> /// <param name="ra"></param> /// <param name="vf"></param> protected virtual async Task HandleRequest(HttpContext context, HttpModuleRequestAssistant ra, IVirtualFileAsync vf) { if (!ra.CachingIndicated && !ra.ProcessingIndicated) { ra.ApplyRewrittenPath(); //This is needed for both physical and virtual files; only makes changes if needed. if (vf != null) { ra.AssignSFH(); //Virtual files are not served in .NET 4. } return; } //Communicate to the MVC plugin this request should not be affected by the UrlRoutingModule. context.Items[conf.StopRoutingKey] = true; context.Items[conf.ResponseArgsKey] = ""; //We are handling the request ra.EstimateResponseInfo(); //Build CacheEventArgs var e = new AsyncResponsePlan(); var modDate = (vf == null) ? System.IO.File.GetLastWriteTimeUtc(ra.RewrittenMappedPath) : (vf is IVirtualFileWithModifiedDateAsync ? await((IVirtualFileWithModifiedDateAsync)vf).GetModifiedDateUTCAsync() : DateTime.MinValue); e.RequestCachingKey = ra.GenerateRequestCachingKey(modDate); var settings = new ResizeSettings(ra.RewrittenInstructions); e.RewrittenQuerystring = settings; e.EstimatedContentType = ra.EstimatedContentType; e.EstimatedFileExtension = ra.EstimatedFileExtension; //A delegate for accessing the source file e.OpenSourceStreamAsync = async delegate() { return((vf != null) ? await vf.OpenAsync() : File.Open(ra.RewrittenMappedPath, FileMode.Open, FileAccess.Read, FileShare.Read)); }; //Add delegate for writing the data stream e.CreateAndWriteResultAsync = async delegate(System.IO.Stream stream, IAsyncResponsePlan plan) { //This runs on a cache miss or cache invalid. This delegate is preventing from running in more //than one thread at a time for the specified cache key try { if (!ra.ProcessingIndicated) { //Just duplicate the data using (Stream source = await e.OpenSourceStreamAsync()) await source.CopyToAsync(stream); //4KiB buffer } else { MemoryStream inBuffer = null; using (var sourceStream = vf != null ? await vf.OpenAsync() : File.Open(ra.RewrittenMappedPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { inBuffer = new MemoryStream(sourceStream.CanSeek ? (int)sourceStream.Length : 128 * 1024); await sourceStream.CopyToAsync(inBuffer); } inBuffer.Seek(0, SeekOrigin.Begin); var outBuffer = new MemoryStream(32 * 1024); //Handle I/O portions of work asynchronously. var j = new ImageJob { Instructions = new Instructions(settings), SourcePathData = vf != null ? vf.VirtualPath : ra.RewrittenVirtualPath, Dest = outBuffer, Source = inBuffer }; await conf.GetImageBuilder().BuildAsync(j, int.MaxValue, CancellationToken.None); outBuffer.Seek(0, SeekOrigin.Begin); await outBuffer.CopyToAsync(stream); } ra.FireJobSuccess(); //Catch not found exceptions } catch (System.IO.FileNotFoundException notFound) { if (notFound.Message.Contains(" assembly ")) { throw; //If an assembly is missing, it should be a 500, not a 404 } //This will be called later, if at all. ra.FireMissing(); throw new ImageMissingException("The specified resource could not be located", "File not found", notFound); } catch (System.IO.DirectoryNotFoundException notFound) { ra.FireMissing(); throw new ImageMissingException("The specified resource could not be located", "File not found", notFound); } catch (Exception ex) { ra.FireJobException(ex); throw; } }; //All bad from here down.... context.Items[conf.ResponseArgsKey] = e; //store in context items //Fire events (for client-side caching plugins) conf.FirePreHandleImageAsync(this, context, e); //Pass the rest of the work off to the caching module. It will handle rewriting/redirecting and everything. //We handle request headers based on what is found in context.Items IAsyncTyrantCache cache = conf.GetAsyncCacheFor(context, e); //Verify we have a caching system if (cache == null) { throw new ImageProcessingException("Image Resizer: No async caching plugin was found for the request"); } await cache.ProcessAsync(context, e); }
public async Task <IVirtualFileAsync> GetFileIfCachedAsync(string virtualPath, NameValueCollection queryString, IVirtualFileAsync original) { //Use alternate cache key if provided string key = original is IVirtualFileSourceCacheKey ? ((IVirtualFileSourceCacheKey)original).GetCacheKey(true) : original.VirtualPath; //If cached, serve it. CachedVirtualFile c = cache.Get(key); if (c != null) { return(c); } //If not, let's cache it. if ("mem".Equals(queryString["scache"], StringComparison.OrdinalIgnoreCase)) { await asyncLocks.TryExecuteAsync(key, 3000, async delegate() { c = cache.Get(key); if (c == null) { using (Stream data = await original.OpenAsync()) {//Very long-running call c = new CachedVirtualFile(original.VirtualPath, await data.CopyToBytesAsync(true, 0x1000)); } cache.Set(key, c);//Save to cache (may trigger cleanup) } }); return(c); } return(null); }
public Task <IVirtualFileAsync> GetFileAsync(string virtualPath, NameValueCollection queryString) { IVirtualFileAsync blobImage = GetBlobFile(virtualPath, queryString); return(Task.FromResult(blobImage)); }
public async Task <IVirtualFileAsync> GetFileIfCachedAsync(string virtualPath, NameValueCollection queryString, IVirtualFileAsync original) { if (!"disk".Equals(queryString["scache"], StringComparison.OrdinalIgnoreCase)) { return(null); } if (!this.AsyncModuleMode) { throw new InvalidOperationException("SourceDiskCache cannot be used in asynchronous mode if AsyncModuleMode=false"); } //Verify web.config exists in the cache folder. writer.CheckWebConfigEvery5(); //Use alternate cache key if provided string key = original is IVirtualFileSourceCacheKey ? ((IVirtualFileSourceCacheKey)original).GetCacheKey(false) : original.VirtualPath; //If cached, serve it. var r = await asyncCache.GetCachedFile(key, ".cache", async delegate(Stream target) { using (Stream data = await original.OpenAsync()) {//Very long-running call await data.CopyToAsync(target); } }, 15 * 1000, true); if (r.Result == CacheQueryResult.Failed) { return(null); } if (r.Result == CacheQueryResult.Hit && cleaner != null) { cleaner.UsedFile(r.RelativePath, r.PhysicalPath); } return(new SourceVirtualFileAsync(original.VirtualPath, delegate() { return Task.FromResult(r.Data ?? File.Open(r.PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.Read)); })); }