Esempio n. 1
0
 public MediaServiceFileSystemAdapter(
     IMediaService mediaService,
     IMediaSearcher mediaSearcher,
     IFolderService folderService,
     IMediaStorageConfiguration storageConfig,
     MediaHelper mediaHelper,
     MediaExceptionFactory exceptionFactory)
 {
     _mediaService        = mediaService;
     _mediaSearcher       = mediaSearcher;
     _folderService       = folderService;
     _mediaHelper         = mediaHelper;
     _storageProvider     = mediaService.StorageProvider;
     _exceptionFactory    = exceptionFactory;
     _mediaRootPath       = storageConfig.PublicPath;
     StorageConfiguration = storageConfig;
 }
Esempio n. 2
0
        public async Task Invoke(
            HttpContext context,
            IMediaService mediaService,
            IFolderService folderService,
            IPermissionService permissionService,
            IWorkContext workContext,
            MediaSettings mediaSettings,
            MediaHelper mediaHelper,
            Lazy <IEnumerable <IMediaHandler> > mediaHandlers,
            ILogger <MediaMiddleware> logger)
        {
            var mediaFileId = context.GetRouteValueAs <int>("id");
            var path        = context.GetRouteValueAs <string>("path");

            if (context.Request.Method != HttpMethods.Get && context.Request.Method != HttpMethods.Head)
            {
                await NotFound(null);

                return;
            }

            var method = context.Request.Method;

            MediaFileInfo mediaFile = null;
            MediaPathData pathData  = null;

            if (mediaFileId == 0)
            {
                // This is most likely a request for a default placeholder image
                pathData = new MediaPathData(path);
            }
            else if (!mediaHelper.TokenizePath(path, false, out pathData))
            {
                // Missing or malformed Uri: get file metadata from DB by id, but only when current user has media manage rights
                if (!(await permissionService.AuthorizeAsync(Permissions.Media.Update)))
                {
                    await NotFound(null);

                    return;
                }

                mediaFile = await mediaService.GetFileByIdAsync(mediaFileId, MediaLoadFlags.AsNoTracking);

                if (mediaFile == null || mediaFile.FolderId == null || mediaFile.Deleted)
                {
                    await NotFound(mediaFile?.MimeType);

                    return;
                }

                pathData = new MediaPathData(folderService.GetNodeById(mediaFile.FolderId.Value), mediaFile.Name)
                {
                    Extension = mediaFile.Extension,
                    MimeType  = mediaFile.MimeType
                };
            }

            var q = await CreateImageQuery(context, pathData.MimeType, pathData.Extension);

            // Security: check allowed thumnail sizes and return 404 if disallowed.
            var thumbMaxWidth    = q.MaxWidth;
            var thumbMaxHeight   = q.MaxHeight;
            var thumbSizeAllowed = IsThumbnailSizeAllowed(thumbMaxWidth) && (thumbMaxHeight == thumbMaxWidth || IsThumbnailSizeAllowed(thumbMaxHeight));

            if (!thumbSizeAllowed)
            {
                await NotFound(pathData.MimeType);

                return;
            }

            // Create the handler context
            var handlerContext = new MediaHandlerContext
            {
                HttpContext       = context,
                CurrentCustomer   = workContext.CurrentCustomer,
                PermissionService = permissionService,
                MediaFileId       = mediaFileId,
                RawPath           = path,
                MediaService      = mediaService,
                PathData          = pathData,
                ImageQuery        = q
            };

            handlerContext.SetSourceFile(mediaFile);

            var handlers = mediaHandlers.Value.OrderBy(x => x.Order).ToArray();

            // Run every registered media handler to obtain a thumbnail for the requested media file
            IMediaHandler currentHandler;

            for (var i = 0; i < handlers.Length; i++)
            {
                currentHandler = handlers[i];

                // Execute handler
                await currentHandler.ExecuteAsync(handlerContext);

                if (handlerContext.Exception != null)
                {
                    var isThumbExtractFail = handlerContext.Exception is ExtractThumbnailException;
                    var statusCode         = isThumbExtractFail ? StatusCodes.Status204NoContent : StatusCodes.Status500InternalServerError;
                    var statusMessage      = isThumbExtractFail ? handlerContext.Exception.InnerException?.Message.EmptyNull() : handlerContext.Exception.Message;

                    await SendStatus(statusCode, statusMessage);

                    return;
                }

                if (handlerContext.Executed || handlerContext.ResultFile != null)
                {
                    // Get out if the handler produced a result file or has been executed in any way
                    break;
                }
            }

            try
            {
                var responseFile = handlerContext.ResultFile ?? await handlerContext.GetSourceFileAsync();

                if (responseFile == null || !responseFile.Exists)
                {
                    await NotFound(pathData.MimeType);

                    return;
                }

                if (string.Equals(responseFile.Extension, "." + pathData.Extension, StringComparison.CurrentCultureIgnoreCase))
                {
                    pathData.MimeType = MimeTypes.MapNameToMimeType(responseFile.Extension);
                }

                // Create FileStreamResult object
                var fileResult = CreateFileResult(responseFile, pathData);

                // Cache control
                ApplyResponseCaching(context, mediaSettings);

                // INFO: Although we are outside of the MVC pipeline we gonna use ActionContext anyway, because "FileStreamResult"
                // does everything we need (ByteRange, ETag etc.), so wo we gonna use it instead of reinventing the wheel.
                // A look at the MVC source code reveals that HttpContext is the only property that gets accessed, therefore we can omit
                // all the other stuff like ActionDescriptor or ModelState (which we cannot access or create from a middleware anyway).
                await fileResult.ExecuteResultAsync(new ActionContext { HttpContext = context, RouteData = context.GetRouteData() });
            }
            finally
            {
                var imageProcessor = context.RequestServices.GetRequiredService <IImageProcessor>();
                logger.Debug("ImageProcessor TOTAL: {0} ms.", imageProcessor.TotalProcessingTimeMs);
            }

            #region Functions

            bool IsThumbnailSizeAllowed(int?size)
            {
                return(size.GetValueOrDefault() == 0 ||
                       mediaSettings.IsAllowedThumbnailSize(size.Value) ||
                       permissionService.Authorize(Permissions.Media.Update, workContext.CurrentCustomer));
            }

            async Task NotFound(string mime)
            {
                context.Response.ContentType = mime.NullEmpty() ?? "text/html";
                context.Response.StatusCode  = 404;
                await context.Response.WriteAsync("404: Not Found");
            }

            async Task SendStatus(int code, string message)
            {
                context.Response.StatusCode = code;
                await context.Response.WriteAsync(message);
            }

            #endregion
        }
        public async Task <MediaFolderInfo> CreateFolderAsync(string path)
        {
            Guard.NotEmpty(path, nameof(path));

            path = FolderService.NormalizePath(path, false);
            ValidateFolderPath(path, "CreateFolder", nameof(path));

            var dupe = _folderService.GetNodeByPath(path);

            if (dupe != null)
            {
                throw _exceptionFactory.DuplicateFolder(path, dupe.Value);
            }

            var  sep         = "/";
            var  folderNames = path.Split(new[] { sep }, StringSplitOptions.RemoveEmptyEntries);
            bool flag        = false;
            int  folderId    = 0;

            path = string.Empty;

            for (int i = 0; i < folderNames.Length; i++)
            {
                var folderName = MediaHelper.NormalizeFolderName(folderNames[i]);
                path += (i > 0 ? sep : string.Empty) + folderName;

                if (!flag)
                {
                    // Find the last existing node in path trail
                    var currentNode = _folderService.GetNodeByPath(path)?.Value;
                    if (currentNode != null)
                    {
                        folderId = currentNode.Id;
                    }
                    else
                    {
                        if (i == 0)
                        {
                            throw new NotSupportedException(T("Admin.Media.Exception.TopLevelAlbum", path));
                        }
                        flag = true;
                    }
                }

                if (flag)
                {
                    using (new DbContextScope(_db, deferCommit: false))
                    {
                        var mediaFolder = new MediaFolder {
                            Name = folderName, ParentId = folderId
                        };
                        _db.MediaFolders.Add(mediaFolder);
                        await _db.SaveChangesAsync();

                        folderId = mediaFolder.Id;
                    }
                }
            }

            return(new MediaFolderInfo(_folderService.GetNodeById(folderId)));
        }