WebMarkupMin icon indicating copy to clipboard operation
WebMarkupMin copied to clipboard

`Response Content-Length mismatch` after `HTML_PARSING_ERROR`

Open AaronLayton opened this issue 8 months ago • 9 comments

Using the following code

<a test=me=hello class="valid-class">
  My Link
</a>

and a standard setup in .NET 8

services.AddWebMarkupMin(options =>
{
    options.AllowMinificationInDevelopmentEnvironment = true;
    options.AllowCompressionInDevelopmentEnvironment = true;
})
    .AddHtmlMinification()
    .AddXmlMinification()
    .AddHttpCompression();

we get the following error message and then no further requests are processed until we restart the app

fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HNDEJGPHCN93", Request id "0HNDEJGPHCN93:0000004D": An unhandled exception was thrown by the application.
      System.InvalidOperationException: Response Content-Length mismatch: too few bytes written (53508 of 318097).

AaronLayton avatar Jun 18 '25 19:06 AaronLayton

Hello, Aaron!

  1. What NuGet package do you have installed: WebMarkupMin.AspNetCore6, WebMarkupMin.AspNetCore7, WebMarkupMin.AspNetCore8 or WebMarkupMin.AspNetCoreLatest?
  2. Which logger do you use: ThrowExceptionLogger, AspNetCoreLogger or some other?

Taritsyn avatar Jun 18 '25 20:06 Taritsyn

Try to reproduce this error in the form of demo project and send me a link to it. Then I'll see how I can fix this problem.

Taritsyn avatar Jun 18 '25 20:06 Taritsyn

Hello, Aaron!

I'm closing this issue for now, because I can't reproduce this error. It is possible that this error occurs when interacting with some third-party Middleware.

Taritsyn avatar Jun 27 '25 12:06 Taritsyn

Potentially - we thought we had fixed it but it cropped up again. I will try and put together a minimal example and see if I can replicate on a clean project 👍

If I can replicate I will open a new issue and reference this one

AaronLayton avatar Jul 03 '25 18:07 AaronLayton

OK

Taritsyn avatar Jul 03 '25 19:07 Taritsyn

Thanks @Taritsyn - massive thanks for your quick replies with this NuGet package as well. Appreciate it!

I think I have narrowed it down to the bellow conditions.

  1. Our site has both
app.UseResponseCompression();
app.UseWebMarkupMin()

We are compressing the output using GZIP / Brotli

  1. Our WebMarkupMin is setup like
services.AddWebMarkupMin(options =>
            {
                options.AllowMinificationInDevelopmentEnvironment = true;
                options.AllowCompressionInDevelopmentEnvironment = true;
            })
                .AddHtmlMinification() // removed 2019-05-01 as it affects CMS Preview
                .AddXmlMinification()
                .AddHttpCompression();

This essentially is doubling up the compression.

When all the HTML is valid, all works well, but if we have the starting HTML as above

<a test=me=hello class="valid-class">
  My Link
</a>

then WebMarkupMin bails out on the minification process and returns the full HTML size. I believe this is causing the issue somewhere along the lines.

If I disable the WebMarkupMin compression line .AddHttpCompression() and just leave the build compression then I do not get the issue

AaronLayton avatar Jul 04 '25 08:07 AaronLayton

Hello, Aaron!

app.UseResponseCompression(); app.UseWebMarkupMin()

It's better not to do this. Perhaps I should explicitly write about this in the documentation.

If I disable the WebMarkupMin compression line .AddHttpCompression() and just leave the build compression then I do not get the issue

It is better to refuse to call the UseResponseCompression method. WebMarkupMin also supports Brotli:

using System.IO.Compression;
…
using WebMarkupMin.AspNet.Common.Compressors;
using WebMarkupMin.AspNetCoreLatest;
using WebMarkupMin.Core;
…

#region Configure services

…
// Add WebMarkupMin services.
services.AddWebMarkupMin(…)
    …
    .AddHttpCompression(options =>
    {
        options.CompressorFactories = new List<ICompressorFactory>
        {
            new BuiltInBrotliCompressorFactory(new BuiltInBrotliCompressionSettings
            {
                Level = CompressionLevel.Fastest
            }),
            new DeflateCompressorFactory(new DeflateCompressionSettings
            {
                Level = CompressionLevel.Fastest
            }),
            new GZipCompressorFactory(new GZipCompressionSettings
            {
                Level = CompressionLevel.Fastest
            })
        };
    })
    ;
…

#endregion
…

then WebMarkupMin bails out on the minification process and returns the full HTML size.

This is completely normal behavior. You can throw an exception if you use a ThrowExceptionLogger:

…
using WebMarkupMin.AspNetCoreLatest;
…

using IWmmLogger = WebMarkupMin.Core.Loggers.ILogger;
using WmmThrowExceptionLogger = WebMarkupMin.Core.Loggers.ThrowExceptionLogger;
…

// Override the default logger for WebMarkupMin.
services.AddSingleton<IWmmLogger, WmmThrowExceptionLogger>();
…

// Add WebMarkupMin services to the services container.
services.AddWebMarkupMin(…)
…

.AddHtmlMinification() // removed 2019-05-01 as it affects CMS Preview

I did not understand the meaning of this line.

I recommend that you read the “ASP.NET Extensions”, “ASP.NET Core Extensions” and “ASP.NET Core Latest” sections of the documentation.

Taritsyn avatar Jul 04 '25 09:07 Taritsyn

Thanks again @Taritsyn

I have made all the changes to my local project and can confirm we are now catching errors. I did add this in so we fallback gracefully in live environments but catch the errors when debugging (simplified for brevity)

var environment = _configuration.GetValue<string>("ASPNETCORE_ENVIRONMENT");
if (environment == "Development")
{
    services.AddSingleton<IWmmLogger, WmmThrowExceptionLogger>();
}
else
{
    services.AddSingleton<IWmmLogger, WmmNullLogger>();
}

and I removed the competing compression as you suggested

AaronLayton avatar Jul 10 '25 16:07 AaronLayton

Excellent!

Taritsyn avatar Jul 10 '25 16:07 Taritsyn