예제 #1
0
        /// <summary>
        /// Provides an end method for an asynchronous process.
        /// </summary>
        /// <param name="result">An IAsyncResult that contains information about the status of the process.</param>
        public void EndProcessRequest(IAsyncResult result)
        {
            // restore the context from the asyncResult.AsyncState
            HttpContext context = ( HttpContext )result.AsyncState;

            if (context != null)
            {
                context.Response.Clear();

                var rockContext = new RockContext();

                bool       requiresViewSecurity = false;
                BinaryFile binaryFile           = new BinaryFileService(rockContext).EndGet(result, context, out requiresViewSecurity);
                if (binaryFile != null)
                {
                    //// if the binaryFile's BinaryFileType requires security, check security
                    //// note: we put a RequiresViewSecurity flag on BinaryFileType because checking security for every file would be slow (~40ms+ per request)
                    if (requiresViewSecurity)
                    {
                        binaryFile.BinaryFileType = binaryFile.BinaryFileType ?? new BinaryFileTypeService(rockContext).Get(binaryFile.BinaryFileTypeId.Value);
                        var    currentUser   = new UserLoginService(rockContext).GetByUserName(UserLogin.GetCurrentUserName());
                        Person currentPerson = currentUser != null ? currentUser.Person : null;

                        if (!binaryFile.IsAuthorized(Authorization.VIEW, currentPerson))
                        {
                            SendError(context, 403, "Not authorized to view file.");
                            return;
                        }
                    }

                    var binaryFileType = BinaryFileTypeCache.Get(binaryFile.BinaryFileTypeId.Value);
                    SendFile(context, binaryFile.ContentStream, binaryFile.MimeType, binaryFile.FileName, binaryFile.Guid.ToString("N"), binaryFileType.CacheControlHeader);
                    return;
                }

                SendError(context, 404, "File could not be found.");
            }
        }
예제 #2
0
        /// <summary>
        /// Processes the binary file request.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ProcessBinaryFileRequest(HttpContext context, RockContext rockContext)
        {
            int  fileId   = context.Request.QueryString["id"].AsInteger();
            Guid fileGuid = context.Request.QueryString["guid"].AsGuid();

            if (fileId == 0 && fileGuid == Guid.Empty)
            {
                SendBadRequest(context, "File id key must be a guid or an int.");
                return;
            }

            var binaryFileQuery = new BinaryFileService(rockContext).Queryable();

            if (fileGuid != Guid.Empty)
            {
                binaryFileQuery = binaryFileQuery.Where(a => a.Guid == fileGuid);
            }
            else
            {
                binaryFileQuery = binaryFileQuery.Where(a => a.Id == fileId);
            }

            //// get just the binaryFileMetaData (not the file content) just in case we can get the filecontent faster from the cache
            //// a null ModifiedDateTime shouldn't happen, but just in case, set it to DateTime.MaxValue so we error on the side of not getting it from the cache
            var binaryFileMetaData = binaryFileQuery.Select(a => new
            {
                a.Id,
                BinaryFileType_CacheToServerFileSystem = a.BinaryFileType.CacheToServerFileSystem,
                BinaryFileType_RequiresViewSecurity    = a.BinaryFileType.RequiresViewSecurity,
                a.BinaryFileTypeId,
                ModifiedDateTime = a.ModifiedDateTime ?? DateTime.MaxValue,
                a.MimeType,
                a.FileName
            }).FirstOrDefault();

            if (binaryFileMetaData == null)
            {
                SendNotFound(context);
                return;
            }

            //// if the binaryFile's BinaryFileType requires view security, check security
            //// note: we put a RequiresViewSecurity flag on BinaryFileType because checking security for every image would be slow (~40ms+ per image request)
            if (binaryFileMetaData.BinaryFileType_RequiresViewSecurity)
            {
                var        currentUser    = new UserLoginService(rockContext).GetByUserName(UserLogin.GetCurrentUserName());
                Person     currentPerson  = currentUser != null ? currentUser.Person : null;
                BinaryFile binaryFileAuth = new BinaryFileService(rockContext).Queryable("BinaryFileType").AsNoTracking().First(a => a.Id == binaryFileMetaData.Id);
                if (!binaryFileAuth.IsAuthorized(Authorization.VIEW, currentPerson))
                {
                    SendNotAuthorized(context);
                    return;
                }
            }


            Stream fileContent = null;

            try
            {
                // Is it cached
                string cacheName          = UrlQueryToCachedFileName(context.Request.QueryString, binaryFileMetaData.MimeType);
                string physCachedFilePath = context.Request.MapPath(string.Format("~/App_Data/Cache/{0}", cacheName));
                if (binaryFileMetaData.BinaryFileType_CacheToServerFileSystem && File.Exists(physCachedFilePath))
                {
                    //// Compare the File's LastWrite DateTime (which comes from the OS's clock), adjust it for the Rock OrgTimeZone, then compare to BinaryFile's ModifiedDateTime (which is already in OrgTimeZone).
                    //// If the BinaryFile record in the database is less recent than the last time this was cached, it is safe to use the Cached version.
                    //// NOTE: A BinaryFile record is typically just added and never modified (a modify is just creating a new BinaryFile record and deleting the old one), so the cached version will probably always be the correct choice.
                    DateTime cachedFileDateTime = RockDateTime.ConvertLocalDateTimeToRockDateTime(File.GetLastWriteTime(physCachedFilePath));
                    if (binaryFileMetaData.ModifiedDateTime < cachedFileDateTime)
                    {
                        // NOTE: the cached file has already been resized (the size is part of the cached file's filename), so we don't need to resize it again
                        fileContent = FetchFromCache(physCachedFilePath);
                    }
                }

                if (fileContent == null)
                {
                    // If we didn't get it from the cache, get it from the binaryFileService
                    BinaryFile binaryFile = GetFromBinaryFileService(context, binaryFileMetaData.Id, rockContext);

                    if (binaryFile != null)
                    {
                        fileContent = binaryFile.ContentStream;
                    }

                    // If we got the image from the binaryFileService, it might need to be resized and cached
                    if (fileContent != null)
                    {
                        // If more than 1 query string param is passed in, or the mime type is TIFF, assume resize is needed
                        // Note: we force "image/tiff" to get resized so that it gets converted into a jpg (browsers don't like tiffs)
                        if (context.Request.QueryString.Count > GetQueryCount(context) || binaryFile.MimeType == "image/tiff")
                        {
                            // if it isn't an SVG file, do a Resize
                            if (binaryFile.MimeType != "image/svg+xml")
                            {
                                fileContent = GetResized(context.Request.QueryString, fileContent);
                            }
                        }

                        if (binaryFileMetaData.BinaryFileType_CacheToServerFileSystem)
                        {
                            Cache(fileContent, physCachedFilePath);

                            // Reset stream
                            if (fileContent.CanSeek)
                            {
                                fileContent.Seek(0, SeekOrigin.Begin);
                            }
                            else
                            {
                                fileContent = FetchFromCache(physCachedFilePath);
                            }
                        }
                    }
                }

                if (fileContent == null)
                {
                    // if we couldn't get the file from the binaryFileServie or the cache, respond with NotFound
                    SendNotFound(context);
                    return;
                }

                // respond with File
                if (binaryFileMetaData.BinaryFileTypeId != null)
                {
                    var binaryFileCache = BinaryFileTypeCache.Get(binaryFileMetaData.BinaryFileTypeId.Value);
                    binaryFileCache.CacheControlHeader.SetupHttpCachePolicy(context.Response.Cache);
                }

                // set the mime-type to that of the binary file
                context.Response.ContentType = binaryFileMetaData.MimeType != "image/tiff" ? binaryFileMetaData.MimeType : "image/jpg";

                // check that the format of the image wasn't changed by a format query parm if so adjust the mime-type to reflect the conversion
                if (context.Request["format"].IsNotNullOrWhiteSpace())
                {
                    switch (context.Request["format"])
                    {
                    case "png":
                    {
                        context.Response.ContentType = "image/png";
                        break;
                    }

                    case "gif":
                    {
                        context.Response.ContentType = "image/gif";
                        break;
                    }

                    case "jpg":
                    {
                        context.Response.ContentType = "image/jpeg";
                        break;
                    }
                    }
                }

                using (var responseStream = fileContent)
                {
                    context.Response.AddHeader("content-disposition", "inline;filename=" + binaryFileMetaData.FileName.MakeValidFileName().UrlEncode());
                    if (responseStream.CanSeek)
                    {
                        responseStream.Seek(0, SeekOrigin.Begin);
                    }
                    responseStream.CopyTo(context.Response.OutputStream);
                    context.Response.Flush();
                }
            }
            finally
            {
                if (fileContent != null)
                {
                    fileContent.Dispose();
                }
            }
        }
예제 #3
0
 /// <summary>
 /// Gets the cache object associated with this Entity
 /// </summary>
 /// <returns></returns>
 public IEntityCache GetCacheObject()
 {
     return(BinaryFileTypeCache.Get(this.Id));
 }
예제 #4
0
 /// <summary>
 /// Updates any Cache Objects that are associated with this entity
 /// </summary>
 /// <param name="entityState">State of the entity.</param>
 /// <param name="dbContext">The database context.</param>
 public void UpdateCache(EntityState entityState, Data.DbContext dbContext)
 {
     BinaryFileTypeCache.UpdateCachedEntity(this.Id, entityState);
 }