smartstore / Smartstore

A modular, scalable and ultra-fast open-source all-in-one eCommerce platform built on ASP.NET Core 7
http://www.smartstore.com/
GNU Affero General Public License v3.0
1.22k stars 453 forks source link

[5.1.0.x] SVG images error on read #882

Open Algorithman opened 1 year ago

Algorithman commented 1 year ago

Describe the bug In ImageHeader.cs method GetPixelSizeFromSvg you need to add the DtdProcessing = DtdProcessing.Parse like this:

line 251: using (var reader = XmlReader.Create(input, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse }))

To Reproduce Steps to reproduce the behavior:

  1. Install smartstore
  2. Create a module which adds a svg file via SampleMediaUtility.CreateMediaFileAsync.
  3. Choose this as company logo or whatever
  4. See error

Desktop (please complete the following information):

Additional context Stacktrace:

UnknownImageFormatException: Image cannot be loaded. Available decoders: - JPEG : JpegDecoder - TIFF : TiffDecoder - GIF : GifDecoder - Webp : WebpDecoder - TGA : TgaDecoder - BMP : BmpDecoder - PBM : PbmDecoder - PNG : PngDecoder
SixLabors.ImageSharp.Formats.ImageFormatManager.ThrowInvalidDecoder(ImageFormatManager manager)
SixLabors.ImageSharp.Image.InternalDetectFormat(Configuration configuration, Stream stream)
SixLabors.ImageSharp.Image.DiscoverDecoder(DecoderOptions options, Stream stream)
SixLabors.ImageSharp.Image.InternalIdentify(DecoderOptions options, Stream stream)
SixLabors.ImageSharp.Image+<>c__DisplayClass76_0.<Identify>b__0(Stream s)
SixLabors.ImageSharp.Image.WithSeekableStream<T>(DecoderOptions options, Stream stream, Func<Stream, T> action)
SixLabors.ImageSharp.Image.Identify(DecoderOptions options, Stream stream)
SixLabors.ImageSharp.Image.Identify(Stream stream)
Smartstore.Imaging.Adapters.ImageSharp.SharpImageFactory.DetectInfo(Stream stream) in SharpImageFactory.cs
+
            var info = Image.Identify(stream);
Smartstore.Imaging.ImageHeader.GetPixelSizeByImageFactory(Stream input, out IImageFormat imageFormat) in ImageHeader.cs
+
            var info = ImageFactory?.DetectInfo(input);
Smartstore.Imaging.ImageHeader.GetPixelSizeWithFormat(Stream input, string mime, bool leaveOpen) in ImageHeader.cs
+
                        var size = GetPixelSizeByImageFactory(input, out var imageFormat);
Smartstore.Imaging.ImageHeader.GetPixelSize(Stream input, string mime, bool leaveOpen) in ImageHeader.cs
+
            return GetPixelSizeWithFormat(input, mime, leaveOpen).Size;
Smartstore.Core.Content.Media.MediaService.EnsureMetadataResolvedAsync(MediaFile file, bool saveOnResolve) in MediaService.cs
+
                        var size = ImageHeader.GetPixelSize(stream, file.MimeType, true);
Smartstore.Core.Content.Media.MediaService.GetFileByIdAsync(int id, MediaLoadFlags flags) in MediaService.cs
+
                await EnsureMetadataResolvedAsync(entity, true);
Smartstore.Core.Content.Media.IMediaServiceExtensions.GetUrlAsync(IMediaService service, Nullable<int> fileId, int thumbnailSize, string host, bool doFallback) in IMediaServiceExtensions.cs
+
            return service.GetUrl(await service.GetFileByIdAsync(fileId ?? 0, MediaLoadFlags.AsNoTracking), query, host, doFallback);
Smartstore.Web.Components.FaviconViewComponent+<>c__DisplayClass2_0+<<InvokeAsync>b__0>d.MoveNext() in FaviconViewComponent.cs
+
                var model = new FaviconModel
Smartstore.Caching.HybridCacheManager.GetAsync<T>(string key, Func<CacheEntryOptions, Task<T>> acquirer, bool independent, bool allowRecursion) in HybridCacheManager.cs
+
                        value = await acquirer(options);
Smartstore.Caching.HybridCacheManager.GetAsync<T>(string key, Func<CacheEntryOptions, Task<T>> acquirer, bool independent, bool allowRecursion) in HybridCacheManager.cs
+
            }
Smartstore.Web.Components.FaviconViewComponent.InvokeAsync() in FaviconViewComponent.cs
+
            var model = await Services.Cache.GetAsync(ModelCacheInvalidator.STORE_FAVICON_MODEL_KEY.FormatInvariant(store.Id), async (o) =>
Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsyncCore(ObjectMethodExecutor executor, object component, ViewComponentContext context)
Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)
Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)
Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentHelper.InvokeCoreAsync(ViewComponentDescriptor descriptor, object arguments)
AspNetCore.Modules_Wissing_Produktdaten_Views_Shared_Layouts__Document.<ExecuteAsync>b__45_1() in _Document.cshtml
+
    @await Component.InvokeAsync("Favicon")
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
AspNetCore.Modules_Wissing_Produktdaten_Views_Shared_Layouts__Document.<ExecuteAsync>b__45_0()
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
AspNetCore.Modules_Wissing_Produktdaten_Views_Shared_Layouts__Document.ExecuteAsync() in _Document.cshtml
+
<html sm-language-attributes-for="WorkContext.WorkingLanguage" data-pnotify-firstpos1="0">
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|22_0(ResourceInvoker invoker, IActionResult result)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|28_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Smartstore.Core.Bootstrapping.CheckoutBootstrappingExtensions+<>c+<<UseCheckoutState>b__0_0>d.MoveNext() in CheckoutBootstrappingExtensions.cs
+
                    await next();
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Smartstore.Web.Api.Startup+<>c+<<BuildPipeline>b__3_6>d.MoveNext() in Startup.cs
+
                            await next(context);
Smartstore.ExceptionExtensions.ReThrow(Exception exception) in ExceptionExtensions.cs
+
            => ExceptionDispatchInfo.Capture(exception).Throw();
Smartstore.Web.Api.Startup.ProcessException(HttpContext context, Exception ex) in Startup.cs
+
                ex.ReThrow();
Smartstore.Web.Api.Startup+<>c+<<BuildPipeline>b__3_6>d.MoveNext() in Startup.cs
+
                            ProcessException(context, ex);
StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in MiniProfilerMiddleware.cs
Smartstore.Core.Localization.RequestCultureMiddleware.Invoke(HttpContext context, IWorkContext workContext) in RequestCultureMiddleware.cs
+
            await _next(context);
Smartstore.Core.Logging.RequestLoggingMiddleware.InvokeAsync(HttpContext httpContext, IWebHelper webHelper, IWorkContext workContext) in RequestLoggingMiddleware.cs
+
                    await _next.Invoke(httpContext);
Smartstore.Core.Bootstrapping.CommonBuilderExtensions+<>c+<<UseWorkContext>b__1_0>d.MoveNext() in CommonBuilderExtensions.cs
+
                await next();
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Smartstore.Core.Bootstrapping.LocalizationBuilderExtensions.OnAfterRouting(HttpContext context, Func<Task> next) in LocalizationBuilderExtensions.cs
+
            await next();
Smartstore.Core.Bootstrapping.LocalizationBuilderExtensions.OnBeforeRouting(HttpContext context, Func<Task> next) in LocalizationBuilderExtensions.cs
+
            await next();
Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.OData.Query.ODataQueryRequestMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.OData.Routing.ODataRouteDebugMiddleware.Invoke(HttpContext context)
Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
Smartstore.Core.Bootstrapping.CommonBuilderExtensions+<>c+<<UseSecurityHeaders>b__3_0>d.MoveNext() in CommonBuilderExtensions.cs
+
                await next(context);
Smartstore.Core.Bootstrapping.CommonBuilderExtensions+<>c+<<UsePoweredBy>b__2_0>d.MoveNext() in CommonBuilderExtensions.cs
+
                await next(context);
Smartstore.Web.Bundling.BundleMiddleware.InvokeAsync(HttpContext httpContext) in BundleMiddleware.cs
+
                await _next(httpContext);
Smartstore.Engine.Initialization.ApplicationInitializerMiddleware.Invoke(HttpContext context) in ApplicationInitializerMiddleware.cs
+
            await _next(context);
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
Algorithman commented 1 year ago

Bit background: I added my logo and favicon via SampleMediaUtility.CreateMediaFileAsync which does not set the pixel width/height in ApplyToStorage since it throws in GetPixelSizeFromSvg so it remains NULL. This in turn leads to this error since the exception is not handled.

This also applies to ico files which are added in the same way. Since width/height 0/0 seems to be enough there maybe a change in public static (Size Size, IImageFormat Format) GetPixelSizeWithFormat(Stream input, string mime, bool leaveOpen = true) with a check for image/x-icon would suffice like this:

if (mime == "image/x-icon")
{
    return (new Size(0,0), null); // No format for ICO
}