TypeError in decode.min.js #372

Closed
opened 2026-01-29 20:42:51 +00:00 by claunia · 5 comments
Owner

Originally created by @stefanloerwald on GitHub (Feb 7, 2021).

Hi, I've just downloaded decode.min.js and integrated it into my app according to the these Microsoft docs.

I get a TypeError: e.Q is not a function.
When pretty-printing the file in dev-tools, the error is in this section of the file:

   // this starts in line 1195 of the prettified code
    function le(e, t, i, n, a, o) {
        var r = Pe(t + i);
        if (r.length != e.length)
            throw "Corrupted brotli dictionary";
        for (var s = 0, l = n.length, c = 0; c < l; c += 2) {
            var d = n.charCodeAt(c) - 36
              , h = n.charCodeAt(c + 1) - 36;
            s += d;
            for (var f = 0; f < h; ++f)
                r[s] |= 128,
                s++
        }
        for (var c = 0; c < o.length; ++c)
            a[c] = o.charCodeAt(c) - 65;
        e.Q(r)
    }

Is this a problem with the minified JS file or with the code calling it?

The code that interacts with brotli is this:

<script src="decode.min.js"></script>
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
<script>
  Blazor.start({
    loadBootResource: function (type, name, defaultUri, integrity) {
      if (type !== 'dotnetjs' && location.hostname !== 'localhost') {
        return (async function () {
          const response = await fetch(defaultUri + '.br', { cache: 'no-cache' });
          if (!response.ok) {
            throw new Error(response.statusText);
          }
          const originalResponseBuffer = await response.arrayBuffer();
          const originalResponseArray = new Int8Array(originalResponseBuffer);
          const decompressedResponseArray = BrotliDecode(originalResponseArray);
          const contentType = type === 
            'dotnetwasm' ? 'application/wasm' : 'application/octet-stream';
          return new Response(decompressedResponseArray, 
            { headers: { 'content-type': contentType } });
        })();
      }
    }
  });
</script>
Originally created by @stefanloerwald on GitHub (Feb 7, 2021). Hi, I've just downloaded decode.min.js and integrated it into my app according to the [these Microsoft docs](https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/webassembly?view=aspnetcore-5.0#compression). I get a `TypeError: e.Q is not a function`. When pretty-printing the file in dev-tools, the error is in this section of the file: ```js // this starts in line 1195 of the prettified code function le(e, t, i, n, a, o) { var r = Pe(t + i); if (r.length != e.length) throw "Corrupted brotli dictionary"; for (var s = 0, l = n.length, c = 0; c < l; c += 2) { var d = n.charCodeAt(c) - 36 , h = n.charCodeAt(c + 1) - 36; s += d; for (var f = 0; f < h; ++f) r[s] |= 128, s++ } for (var c = 0; c < o.length; ++c) a[c] = o.charCodeAt(c) - 65; e.Q(r) } ``` Is this a problem with the minified JS file or with the code calling it? The code that interacts with brotli is this: ```html <script src="decode.min.js"></script> <script src="_framework/blazor.webassembly.js" autostart="false"></script> <script> Blazor.start({ loadBootResource: function (type, name, defaultUri, integrity) { if (type !== 'dotnetjs' && location.hostname !== 'localhost') { return (async function () { const response = await fetch(defaultUri + '.br', { cache: 'no-cache' }); if (!response.ok) { throw new Error(response.statusText); } const originalResponseBuffer = await response.arrayBuffer(); const originalResponseArray = new Int8Array(originalResponseBuffer); const decompressedResponseArray = BrotliDecode(originalResponseArray); const contentType = type === 'dotnetwasm' ? 'application/wasm' : 'application/octet-stream'; return new Response(decompressedResponseArray, { headers: { 'content-type': contentType } }); })(); } } }); </script> ```
Author
Owner

@stefanloerwald commented on GitHub (Feb 10, 2021):

I had a deeper look into the javascript and the minified version is obviously invalid: The corresponding code unminified is:

  function unpackDictionaryData(dictionary, data0, data1, skipFlip, sizeBits, sizeBitsData) {
    var /** @type{!Int8Array} */ dict = toUsAsciiBytes(data0 + data1);
    if (dict.length != dictionary.length) {
      throw "Corrupted brotli dictionary";
    }
    var /** @type{number} */ offset = 0;
    var /** @type{number} */ n = skipFlip.length;
    for (var /** @type{number} */ i = 0; i < n; i += 2) {
      var /** @type{number} */ skip = skipFlip.charCodeAt(i) - 36;
      var /** @type{number} */ flip = skipFlip.charCodeAt(i + 1) - 36;
      offset += skip;
      for (var /** @type{number} */ j = 0; j < flip; ++j) {
        dict[offset] |= 0x80;
        offset++;
      }
    }
    for (var /** @type{number} */ i = 0; i < sizeBitsData.length; ++i) {
      sizeBits[i] = sizeBitsData.charCodeAt(i) - 65;
    }
    dictionary.set(dict);
  }

There is exactly one call to this method, and it's four lines further down:

    var /** @type{!Int8Array} */ dictionaryData = new Int8Array(122784);
    var /** @type{!Int32Array} */ dictionarySizeBits = new Int32Array(25);
    unpackDictionaryData(dictionaryData, "...

So it's obvious, that the first arg to the method is of type Int8Array. The minifier replaced set by Q, which is nonsense. So this was created by an overly aggressive minifier.

The attached minified version was generated using the following Dockerfile:

FROM node
WORKDIR /src
RUN npm i minify -g
RUN wget https://github.com/google/brotli/raw/master/js/decode.js
RUN minify decode.js > decode.min.js

Until the actual build pipeline for these files is fixed, I'd suggest to simply replace the files with the ones attached.

BR
Stefan

(Note: a previous version of this comment incorrectly stated that there was unused code in the JS file. I apologise for this mistake. However, the analysis that the minified file is not working still stands)

@stefanloerwald commented on GitHub (Feb 10, 2021): I had a deeper look into the javascript and the minified version is obviously invalid: The corresponding code unminified is: ```js function unpackDictionaryData(dictionary, data0, data1, skipFlip, sizeBits, sizeBitsData) { var /** @type{!Int8Array} */ dict = toUsAsciiBytes(data0 + data1); if (dict.length != dictionary.length) { throw "Corrupted brotli dictionary"; } var /** @type{number} */ offset = 0; var /** @type{number} */ n = skipFlip.length; for (var /** @type{number} */ i = 0; i < n; i += 2) { var /** @type{number} */ skip = skipFlip.charCodeAt(i) - 36; var /** @type{number} */ flip = skipFlip.charCodeAt(i + 1) - 36; offset += skip; for (var /** @type{number} */ j = 0; j < flip; ++j) { dict[offset] |= 0x80; offset++; } } for (var /** @type{number} */ i = 0; i < sizeBitsData.length; ++i) { sizeBits[i] = sizeBitsData.charCodeAt(i) - 65; } dictionary.set(dict); } ``` There is exactly one call to this method, and it's four lines further down: ```js var /** @type{!Int8Array} */ dictionaryData = new Int8Array(122784); var /** @type{!Int32Array} */ dictionarySizeBits = new Int32Array(25); unpackDictionaryData(dictionaryData, "... ``` So it's obvious, that the first arg to the method is of type `Int8Array`. The minifier replaced `set` by `Q`, which is nonsense. So this was created by an overly aggressive minifier. The [attached minified version](https://github.com/google/brotli/files/5963966/decode.min.js.zip) was generated using the following Dockerfile: ```Dockerfile FROM node WORKDIR /src RUN npm i minify -g RUN wget https://github.com/google/brotli/raw/master/js/decode.js RUN minify decode.js > decode.min.js ``` Until the actual build pipeline for these files is fixed, I'd suggest to simply replace the files with the ones attached. BR Stefan (Note: a previous version of this comment incorrectly stated that there was unused code in the JS file. I apologise for this mistake. However, the analysis that the minified file is not working still stands)
Author
Owner

@stefanloerwald commented on GitHub (Jun 4, 2021):

It's been months on this topic without any response. I must say I find it bizarre that such a trivially fixable issue isn't even responded to. Clearly other people are affected too. Please just use a non-broken minifier to produce a correct version of your code.

Thanks
Stefan

@stefanloerwald commented on GitHub (Jun 4, 2021): It's been months on this topic without any response. I must say I find it bizarre that such a trivially fixable issue isn't even responded to. Clearly other people are affected too. Please just use a non-broken minifier to produce a correct version of your code. Thanks Stefan
Author
Owner

@eustas commented on GitHub (Jun 24, 2021):

Hello. Sorry for the super-long delay. Could you, please, check that decode.min.js works for you now?

@eustas commented on GitHub (Jun 24, 2021): Hello. Sorry for the super-long delay. Could you, please, check that decode.min.js works for you now?
Author
Owner

@eustas commented on GitHub (Jun 24, 2021):

Important: now decode.js / decode.min.js is a module; so the updated usage example looks like this:

<html>
<body>
  <script type="module">
    import {BrotliDecode} from './decode.min.js';
    let ukkonooa = [
      0x1b, 0x76, 0x00, 0x00, 0x14, 0x4a, 0xac, 0x9b, 0x7a, 0xbd, 0xe1, 0x97,
      0x9d, 0x7f, 0x8e, 0xc2, 0x82, 0x36, 0x0e, 0x9c, 0xe0, 0x90, 0x03, 0xf7,
      0x8b, 0x9e, 0x38, 0xe6, 0xb6, 0x00, 0xab, 0xc3, 0xca, 0xa0, 0xc2, 0xda,
      0x66, 0x36, 0xdc, 0xcd, 0x80, 0x8d, 0x2e, 0x21, 0xd7, 0x6e, 0xe3, 0xea,
      0x4c, 0xb8, 0xf0, 0xd2, 0xb8, 0xc7, 0xc2, 0x70, 0x4d, 0x3a, 0xf0, 0x69,
      0x7e, 0xa1, 0xb8, 0x45, 0x73, 0xab, 0xc4, 0x57, 0x1e
    ];
    let lyrics = BrotliDecode(new Uint8Array(ukkonooa));
    console.log(String.fromCharCode.apply(null, new Uint16Array(lyrics)));
  </script>
</body>
</html>
@eustas commented on GitHub (Jun 24, 2021): Important: now decode.js / decode.min.js is a module; so the updated usage example looks like this: ``` <html> <body> <script type="module"> import {BrotliDecode} from './decode.min.js'; let ukkonooa = [ 0x1b, 0x76, 0x00, 0x00, 0x14, 0x4a, 0xac, 0x9b, 0x7a, 0xbd, 0xe1, 0x97, 0x9d, 0x7f, 0x8e, 0xc2, 0x82, 0x36, 0x0e, 0x9c, 0xe0, 0x90, 0x03, 0xf7, 0x8b, 0x9e, 0x38, 0xe6, 0xb6, 0x00, 0xab, 0xc3, 0xca, 0xa0, 0xc2, 0xda, 0x66, 0x36, 0xdc, 0xcd, 0x80, 0x8d, 0x2e, 0x21, 0xd7, 0x6e, 0xe3, 0xea, 0x4c, 0xb8, 0xf0, 0xd2, 0xb8, 0xc7, 0xc2, 0x70, 0x4d, 0x3a, 0xf0, 0x69, 0x7e, 0xa1, 0xb8, 0x45, 0x73, 0xab, 0xc4, 0x57, 0x1e ]; let lyrics = BrotliDecode(new Uint8Array(ukkonooa)); console.log(String.fromCharCode.apply(null, new Uint16Array(lyrics))); </script> </body> </html> ```
Author
Owner

@stefanloerwald commented on GitHub (Jun 25, 2021):

Hi @eustas,

I can confirm that the new version works. Thank you.

Best regards
Stefan

@stefanloerwald commented on GitHub (Jun 25, 2021): Hi @eustas, I can confirm that the new version works. Thank you. Best regards Stefan
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/brotli#372