itchio / itch.io

:bug: Public itch.io issues tracker and documentation - use support instead for private information!
https://itch.io/support
241 stars 27 forks source link

Blazor/Wasm games with Brotli compression/decompression are broken. #1512

Open nkast opened 1 year ago

nkast commented 1 year ago

Recently html games that are written in Blazor/Wasm stopped working. The reported game is https://kwyrky.itch.io/blazorwasmgame1 My own game has the same issue: https://nkast.itch.io/alienexterminator

Those games were written in KNI, a C# game framework, and make use of the decode.js library to uncompressed the *.br files generated by Blazor webassembly. host-and-deploy webassembly-compression

The error occurs in this line where BrotliDecode(...) is called to decompress '_framework/blazor.boot.json.br'. decode.js throws a '"Corrupted padding bits"'

Http-Request

GET /html/7196597/_framework/blazor.boot.json.br HTTP/2
Host: html-classic.itch.zone
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://html-classic.itch.zone/html/7196597/index.html
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Pragma: no-cache
Cache-Control: no-cache
TE: trailers

Http-Response

HTTP/2 200 
x-guploader-uploadid: ABPtcPqBqJFTH65zHX9-vY4tOHJze-OlHY8uyzNhiZF1tqlkcl4g6qTVAoYrCtr2aYhwNao40wY
last-modified: Sat, 21 Jan 2023 02:31:15 GMT
etag: "b68ade5c91657c3c379bb1190c50e571"
x-goog-generation: 1674268275595169
x-goog-metageneration: 1
x-goog-stored-content-encoding: br
x-goog-stored-content-length: 3132
content-type: application/json
x-goog-hash: crc32c=Z0F9oQ==
x-goog-hash: md5=toreXJFlfDw3m7EZDFDlcQ==
x-goog-storage-class: STANDARD
server: UploadServer
content-encoding: gzip
content-length: 3384
cache-control: public, max-age=2157
date: Mon, 27 Nov 2023 09:16:26 GMT
vary: Accept-Encoding
X-Firefox-Spdy: h2

{
  "cacheBootResources": true,
  "config": [ ],
  "debugBuild": false,
  "entryAssembly": "WebGLxna",
  "icuDataMode": 0,
  "linkerEnabled": true,
  "resources": {
    "assembly": {
      "Aether.Components.dll": "sha256-Cyj7\/zMrN2LTKO43UoeNFLBcazRZ6cJJNbL1rYAO9Ys=",
      "Aether.dll": "sha256-QIrKQ0FXbFxIMQdsYQPJCEOVAs85EtNMjAxVAmPAUY8=",
      "Aether.Particles.dll": "sha256-TrBvk5FcMDAkKbfmmlTqQGHIkAP2yY0L8V+2S0VnFxQ=",
      "Aether.Physics2D.Components.dll": "sha256-we+CVYT9Llx\/5rJYTZKFvC9KSlJnbZr4SExekQ1fipk=",
      "Aether.Physics2D.dll": "sha256-atwP6WdbA+OrkLSPdqDWizsTnQYLpsZn+fI52FFYOs0=",
      "MGJ3.Components.dll": "sha256-kxsmOwDF9HQgkIzuphBuZ5sRlcs0DeOOYyzNYPyGS5g=",
      "Microsoft.AspNetCore.Components.dll": "sha256-xv2jmxV8msKL2kdZk\/R+YdrKMoN55RbhYmXvPKTTgW4=",
      "Microsoft.AspNetCore.Components.Web.dll": "sha256-qU3IAmEqXKihCR1jmqNwiQI3vuEaPjNm9Fl+CA7mchs=",
      "Microsoft.AspNetCore.Components.WebAssembly.dll": "sha256-2n94FDGpkN1cvoXLu6PLx58lOudbge2yTEEF195Di30=",
      "Microsoft.Extensions.Configuration.Abstractions.dll": "sha256-yNUivmV4a48Mkbc1Sz+XJ9Y8moJKjWJo6Z0haFMFrKQ=",
      "Microsoft.Extensions.Configuration.dll": "sha256-OWH+xkIa4nRWGQutqm7dxgAY22jFGJlC+P6RzpDPrBE=",
      "Microsoft.Extensions.Configuration.Json.dll": "sha256-boSewHLerYdMMQk1EahIMSbAXSrf7Kgky4CGjZ3uuto=",
      "Microsoft.Extensions.DependencyInjection.Abstractions.dll": "sha256-eGWqw+M+dcThgPODjYDXobi9osfn3x1sGnbNgacKzbI=",
      "Microsoft.Extensions.DependencyInjection.dll": "sha256-azTt1JLi4RL0qaUPW8um+3BlO1IxYfZUaUP+kmJ6E6Y=",
      "Microsoft.Extensions.Logging.Abstractions.dll": "sha256-HvvXTIFdkrXJb\/BAlYnHIU4556GzDx2XYYQnhnWsP9I=",
      "Microsoft.Extensions.Logging.dll": "sha256-uvQcmI6XrSMo7BLb8B56Haq\/wjzfQPy1LJw48RmEmDs=",
      "Microsoft.Extensions.Options.dll": "sha256-T5jVw2iu5DWOW7fDB+sTItI3LDyjsz2wT4pCJl0cma8=",
      "Microsoft.Extensions.Primitives.dll": "sha256-Kk9trPYi6xuop+bJh7AertZVcNJkEyzyxW3andlyf5U=",
      "Microsoft.JSInterop.dll": "sha256-FmWkCNSUWh9oEGa1sKhfxQ\/3ydOlciEtF2lyI3hUKbI=",
      "Microsoft.JSInterop.WebAssembly.dll": "sha256-5rjENboVhqNLvFRQlepT4PYJ6Jo8jamVzm\/ujRo7Qd4=",
      "Monogame.Framework.dll": "sha256-udgVebSPs4OPrt5\/KrZf1Y982kMqt8uauUxOV96cbT8=",
      "netstandard.dll": "sha256-Y2RIgX8tF9CAsEJMPEo5IRCcGfoiHDNSsbU3fQ+g8rw=",
      "nkast.Wasm.Audio.dll": "sha256-j55hKWN0pxGjNQMPQK1cUlJoKyk9DZI4vwjxZQXru3M=",
      "nkast.Wasm.Canvas.dll": "sha256-+kIcf7Lh97eDebaKgg2kitRIFXlhN1lgdwlR+9N5y90=",
      "nkast.Wasm.Dom.dll": "sha256-htsmTghA9VYd3vz6u5ASzEctD5v+6+VbTF9qEzMuW1s=",
      "nkast.Wasm.XHR.dll": "sha256-oJpMDhHHsNmkS2WlDOVDcKVKiu4CADSsuL5eetCS6MU=",
      "System.Collections.Concurrent.dll": "sha256-XA52uX8TsjI9GZvSs02xcL9+ZexFANf0kvVZt+7o1OU=",
      "System.Collections.dll": "sha256-wJLnuawl7JIy+eZKhIyN5dwcakAFh4JWM6OMnQ3JAR4=",
      "System.Collections.NonGeneric.dll": "sha256-vAsxWU+7\/JufyHiXYFuyODHJFd\/HXeEiUHgFruPvbu4=",
      "System.Collections.Specialized.dll": "sha256-Zf8F7ZibhacBKk2ZD6zb6ft8zggv5xJU+NGRvZICezY=",
      "System.ComponentModel.dll": "sha256-1VjKvt9RUXsCbk2ICef0i1HEnLOupAC17JQmeJ\/ysDM=",
      "System.ComponentModel.Primitives.dll": "sha256-P+j\/5aboYiwq+20LYFevMUuMvau3aUxsV6+XBxIRbMc=",
      "System.ComponentModel.TypeConverter.dll": "sha256-xZ1s9OWeIe1QezJmj8OMOYBtPgtTHIo1rFlvQLi04mY=",
      "System.Console.dll": "sha256-1kJZZ5hAU9rQnMGsSxJqK1+IcK5VcgsO\/PgvHZ3sRsQ=",
      "System.Diagnostics.TraceSource.dll": "sha256-QQOK8atu7lt9vtKjzv3LcAKA74UnVMFCl3yXgHmfmtg=",
      "System.dll": "sha256-3Dx96Y+RlO\/k82GuDMLHREDY0XtFkReumxgF4OwQta4=",
      "System.Drawing.dll": "sha256-QSugHe2cbrehw8VEdBp11vqYVGYlsrIcsksevcxBTzU=",
      "System.Drawing.Primitives.dll": "sha256-Pz7IUwSMaP3D3d24nAQO8Gm4S2\/BcnT85+bMTtVBuAQ=",
      "System.Linq.dll": "sha256-PuEOeyYuI2ud9UPsZaYw6tdyY2J+TpYf60a8GRAsxj8=",
      "System.Linq.Expressions.dll": "sha256-C9Gi327cS+1BCm1M+2d4MAcTWam4Naqeu334pNjkfyM=",
      "System.Memory.dll": "sha256-Xi5ebfW554K0XPO+TJQ4E7cZRlFnGZEGI7+PfZsfmlc=",
      "System.Net.Http.dll": "sha256-Zu0C3iUH3OHFUVtabzrRYz0ciMk3WWcaJd9dKuoznvE=",
      "System.Net.Primitives.dll": "sha256-J9wrX+oYnAGov96QQeFR5+lB2h\/wnToRYynILnOhJQc=",
      "System.ObjectModel.dll": "sha256-MW65WUXA8yjRIJ6974HBqiURS827HbM3\/NE0MifdRXo=",
      "System.Private.CoreLib.dll": "sha256-fFZ9+G47qIdYr3QvBuwTh463T5fJJbn7Qc5SYTXQS0Y=",
      "System.Private.Runtime.InteropServices.JavaScript.dll": "sha256-F1pGM1l\/0Byi+8eAlus5ZuglMGoMTcjgOwU7gbstBoI=",
      "System.Private.Uri.dll": "sha256-HlyFP2Jc7vHMc19Ktb+hbmZ1weKvW6Ja7i3JKvASTZk=",
      "System.Private.Xml.dll": "sha256-OORGpQ2DVHI6cx29ueh+NlPzYok\/Nq9C+3JUdcHeO90=",
      "System.Runtime.CompilerServices.Unsafe.dll": "sha256-Cor0KCrsvgrEKmpSxuHFQcWmmm0sJn\/NiRRKNI1OLSk=",
      "System.Runtime.dll": "sha256-eZA4\/OkpKE2fUkRfUcEqsiZBVyK\/C+7r2mKdZfvdeGc=",
      "System.Runtime.InteropServices.dll": "sha256-t3lctenFHR2Quc2QH7iSvdp6Nb49ngNVewQoZOft3RU=",
      "System.Runtime.Serialization.Primitives.dll": "sha256-IfNOEC1cMK1T068Wc9XKU4TlTZnCTKqSgDOXwE7WKdw=",
      "System.Security.Cryptography.Algorithms.dll": "sha256-SCXk2hFmLNy6insstik\/lGXs2m1zGGcAFqlf0wdvK\/M=",
      "System.Security.Cryptography.Primitives.dll": "sha256-VXl2N89JxdrjAUAjVcRFd7Mdci75tWW9EwCyZnKCmgc=",
      "System.Text.Encoding.Extensions.dll": "sha256-ocu2wtdNl7+oATXgh5V8ka2TWcg7RIyMkDkoOXDwVUI=",
      "System.Text.Encodings.Web.dll": "sha256-oUsmj73hwCUgOH1k3iNuvk2WZyKwOYVokxswyU7aNGA=",
      "System.Text.Json.dll": "sha256-wg7PSZVulfoSRxzumuIvqLNyI4ZngUVHjl0NT95ltmM=",
      "System.Text.RegularExpressions.dll": "sha256-SH5KNXYrOWgyQa3d\/uuc8Q5u9rXgsOVo3s2cpg\/i5kY=",
      "System.Threading.dll": "sha256-20PawtJ+\/wVpj9n1mYzo2FtjKtWH6Y38WAVWsGnRbEg=",
      "System.Threading.Tasks.Parallel.dll": "sha256-37t4+NXpUX\/625TtjjslEjnMtNXn+xWvaDZGhMLsUS8=",
      "System.Threading.Thread.dll": "sha256-VxJMSz2ebd0Kif\/yGqDSFlVu6J2DJKqZZipJ8bLC2GU=",
      "WebGLxna.dll": "sha256-vEeZLHRqaEYA\/LPcrvH1aSicGZVIDhaifdzMd1Zry9E=",
      "XNALibrary.NETSTANDARD2_0.dll": "sha256-xDokAhrH2R2ejQN2N2LASQIA+q\/8f5PhugexUBkX5SE="
    },
    "extensions": null,
    "lazyAssembly": null,
    "libraryInitializers": null,
    "pdb": null,
    "runtime": {
      "dotnet.6.0.13.d3s7d5xanr.js": "sha256-socY77ojRqzllaVfYYgopToXg9oEaDSaOf84P87brGM=",
      "dotnet.wasm": "sha256-\/j2D4Jx0xps0WGMa82OJji+UzMImJIgvLSkYHLp6uQY=",
      "icudt.dat": "sha256-Zuq0dWAsBm6\/2lSOsz7+H9PvFaRn61KIXHMMwXDfvyE=",
      "icudt_CJK.dat": "sha256-WPyI4hWDPnOw62Nr27FkzGjdbucZnQD+Ph+GOPhAedw=",
      "icudt_EFIGS.dat": "sha256-4RwaPx87Z4dvn77ie\/ro3\/QzyS+\/gGmO3Y\/0CSAXw4k=",
      "icudt_no_CJK.dat": "sha256-OxylFgLJlFqixsj+nLxYVsv5iZLvfIKMpLf9hrWaChA="
    },
    "runtimeAssets": {
      "dotnet.wasm": {
        "behavior": "dotnetwasm",
        "hash": "sha256-\/j2D4Jx0xps0WGMa82OJji+UzMImJIgvLSkYHLp6uQY="
      }
    },
    "satelliteResources": null
  }
}
nkast commented 1 year ago

I updated the http request/response as captured by Firefox. I also removed the .gz files from the Web.zip of my game and re-uploaded.

I requested both 'blazor.boot.json' and 'blazor.boot.json.br': both files return as gzip compressed,

content-encoding: gzip
content-length: 3384

There is a difference in the 'x-goog-stored-content' headers blazor.boot.json:

x-goog-stored-content-encoding : identity
x-goog-stored-content-length : 7054

blazor.boot.json.br:

x-goog-stored-content-encoding : br
x-goog-stored-content-length : 3132

The file I finally get from the fetch() method is the plaintext of 'blazor.boot.json' ! It is clear that the server, 1) decompress the 'blazor.boot.json.br' file on the fly. (???) 2) Recompress it as gzip on the fly.

What I would expect is to receive the compressed brotli content of 'blazor.boot.json.br' in the response body. Regardless of whether it goes through gz compression or not. There has to be a recent change on the server configuration because everything was working fine a while ago.

leafo commented 1 year ago

Thank you for the detailed report.

Our old CDN company was bought out by Akamai and we had to migrate to their platform last week (Full migration completed on Nov 22). Unfortunately, the integration Akamai provided subtly (and no so subtly) failing us in many ways.

I'll go through the configuration to see if I can identify differences in how automatic compression is happening.

Just so you are aware, though, we do some funky stuff with the .br extension as a workaround for certain Unity Exports. Here's the documentation on the expected behavior:

https://itch.io/docs/creators/html5#compression

If the filename ends with the extension .br then we'll assume that the content is Brotli compressed and the content-encoding will bet set to br. The The content-type header of the file will then be detected and set by the extension, after removing the .br. (Note: Brotli encoding can not be detected like gzip, so we must depend on the .br extension). This approach is commonly used by Unity 2020 WebGL export.

https://github.com/itchio/zipserver/blob/master/zipserver/archive.go#L326