umbraco / Umbraco.StorageProviders

MIT License
29 stars 21 forks source link

Retreiving file with 1.1.0 results in FormatException: Invalid ETag name error. #37

Closed KevinJump closed 2 years ago

KevinJump commented 2 years ago

Hi,

Following the documented setup: https://our.umbraco.com/documentation/Extending/FileSystemProviders/Azure-Blob-Storage/

And installing the latest version of the blob provider (1.1.0) - files will upload to the blob storage fine (checked that) but when your site attempts to retrieve them, you get a "FormatException: Invalid ETag" name error -

Note: Downgrading the package to 1.0.0 - resolves this issue

Steps:

  1. Create some blob storage add the config to appsettings.json
  "Umbraco": {
    "Storage": {
      "AzureBlob": {
        "Media": {
          "ConnectionString": "****CONNECTION STRING*****",
          "ContainerName": "*****BLOB/CONTAINER NAME****"
        }
      }
    },
  1. Upload a file via the media section
  2. Click on media image doesn't load

File will be in blob storage, but logs will show error:

An unhandled exception has occurred while executing the request.
System.FormatException: Invalid ETag name
   at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag, Boolean isWeak)
   at Umbraco.StorageProviders.AzureBlob.AzureBlobFileSystemMiddleware.HandleRequestAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Umbraco.Cms.Web.Common.Middleware.BasicAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Umbraco.Cms.Web.BackOffice.Middleware.BackOfficeExternalLoginProviderErrorMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in C:\projects\dotnet\src\MiniProfiler.AspNetCore\MiniProfilerMiddleware.cs:line 121
   at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Umbraco.Cms.Web.Common.Middleware.PreviewAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestLoggingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---

Downgrade your site to use 1.0.0 of the page image will be loaded.

ronaldbarendse commented 2 years ago

Thanks for reporting this @KevinJump, looks like ETag handling is a bit quirky with Azure Blob Storage 😞

The first issue and PR are related to adding quotes around the value to fix this exact error (see https://github.com/umbraco/Umbraco.StorageProviders/pull/2), this was fixed even before v1.0.0 was publicly released. In v1.1.0 the Azure.Storage.Blobs dependency was updated from 12.10.0 to 12.11.0 and because that fixed a bug/regression regarding ETag quotation marks (see release notes), this got changed to use ToString("H") to property format the value (and prevent both missing or double quotes).

Can you report back what version of Azure.Storage.Blobs you have installed and what request/service version is used (because that might return different results)?

The request/service version relates to how the request is authorized, so check the sv query string in your connection string (if you're using a Shared Access Signature). Multiple of my Umbraco Cloud projects run v1.1.0 using Azure.Storage.Blobs 12.11.0 and service version 2019-07-07 without any issues...

ronaldbarendse commented 2 years ago

OK, so third time's a charm:

using Azure;
using System.Net.Http.Headers;

ETag tag;

tag = new ETag("sometag");
Console.WriteLine(new EntityTagHeaderValue($"\"{tag}\""));
Console.WriteLine(new EntityTagHeaderValue(tag.ToString("H")));
Console.WriteLine(EntityTagHeaderValue.Parse(tag.ToString("H")));

tag = new ETag("\"sometag\"");
//Console.WriteLine(new EntityTagHeaderValue($"\"{tag}\"")); // Invalid tag because of double quotes
Console.WriteLine(new EntityTagHeaderValue(tag.ToString("H")));
Console.WriteLine(EntityTagHeaderValue.Parse(tag.ToString("H")));

tag = new ETag("\"sometag\"");
//Console.WriteLine(new EntityTagHeaderValue($"\"{tag}\"")); // Invalid tag because of double quotes
Console.WriteLine(new EntityTagHeaderValue(tag.ToString("H")));
Console.WriteLine(EntityTagHeaderValue.Parse(tag.ToString("H")));

tag = new ETag("W/\"sometag\"");
//Console.WriteLine(new EntityTagHeaderValue($"\"{tag}\"")); // Invalid tag because of double quotes
//Console.WriteLine(new EntityTagHeaderValue(tag.ToString("H"))); // Invalid tag, because of the leading W/
Console.WriteLine(EntityTagHeaderValue.Parse(tag.ToString("H")));

@KevinJump Can you get the ETag value for the file that caused the exception (e.g. using the Azure Portal or Storage Explorer) and verify whether it contains the weak validator?