/// <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;

            try
            {
                context.Response.Clear();

                bool isBinaryFile = (bool)context.Items["isBinaryFile"];

                if ( isBinaryFile )
                {
                    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 )
                        {
                            var currentUser = new UserLoginService( rockContext ).GetByUserName( UserLogin.GetCurrentUserName() );
                            Person currentPerson = currentUser != null ? currentUser.Person : null;
                            binaryFile.BinaryFileType = binaryFile.BinaryFileType ?? new BinaryFileTypeService( rockContext ).Get( binaryFile.BinaryFileTypeId.Value );
                            if ( !binaryFile.IsAuthorized( Authorization.VIEW, currentPerson ) )
                            {
                                SendNotAuthorized( context );
                                return;
                            }
                        }

                        SendFile( context, binaryFile.ContentStream, binaryFile.MimeType, binaryFile.FileName, binaryFile.Guid.ToString("N") );
                        return;
                    }
                }
                else
                {
                    Stream fileContents = (Stream)context.Items["fileContents"];
                    string physicalContentFileName = context.Items["physicalContentFileName"] as string;

                    if ( fileContents != null )
                    {
                        string mimeType = System.Web.MimeMapping.GetMimeMapping( physicalContentFileName );
                        string fileName = Path.GetFileName( physicalContentFileName );
                        SendFile( context, fileContents, mimeType, fileName, "" );
                        return;
                    }
                }

                context.Response.StatusCode = 404;
                context.Response.StatusDescription = "Unable to find the requested file.";
            }
            catch ( Exception ex )
            {
                ExceptionLogService.LogException( ex, context );
                try
                {
                    context.Response.StatusCode = 500;
                    context.Response.StatusDescription = ex.Message;
                    context.Response.Flush();
                    context.ApplicationInstance.CompleteRequest();
                }
                catch ( Exception ex2 )
                {
                    ExceptionLogService.LogException( ex2, context );
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Processes the binary file request.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ProcessBinaryFileRequest( HttpContext context )
        {
            int fileId = context.Request.QueryString["id"].AsInteger() ?? 0;
            Guid fileGuid = context.Request.QueryString["guid"].AsGuid();

            if ( fileId == 0 && fileGuid.Equals( Guid.Empty ) )
            {
                SendNotFound( context );
            }

            var rockContext = new RockContext();

            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
            {
                BinaryFileType_AllowCaching = a.BinaryFileType.AllowCaching,
                BinaryFileType_RequiresSecurity = a.BinaryFileType.RequiresSecurity,
                ModifiedDateTime = a.ModifiedDateTime ?? DateTime.MaxValue,
                a.MimeType,
                a.FileName
            } ).FirstOrDefault();

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

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

            byte[] fileContent = null;

            // 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_AllowCaching && File.Exists( physCachedFilePath ) )
            {
                //// Compare the File's Creation 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.GetCreationTime( 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, fileId, fileGuid );

                if ( binaryFile != null && binaryFile.Data != null )
                {
                    fileContent = binaryFile.Data.Content;
                }

                // 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, assume resize is needed
                    if ( context.Request.QueryString.Count > 1 )
                    {
                        // 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_AllowCaching )
                    {
                        Cache( fileContent, 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
            context.Response.ContentType = binaryFileMetaData.MimeType;
            context.Response.AddHeader( "content-disposition", "inline;filename=" + binaryFileMetaData.FileName );
            if ( binaryFileMetaData.BinaryFileType_AllowCaching )
            {
                // if binaryFileType is set to allowcaching, also tell the browser to cache it for 365 days
                context.Response.Cache.SetLastModified( binaryFileMetaData.ModifiedDateTime );
                context.Response.Cache.SetMaxAge( new TimeSpan( 365, 0, 0, 0 ) );
            }

            context.Response.BinaryWrite( fileContent );
            context.Response.Flush();
        }