(buffer: Uint8Array)
| 30 | private compatAdapter: CompatAdapter; |
| 31 | |
| 32 | constructor(buffer: Uint8Array) { |
| 33 | const wbn = asArray(cborg.decode(buffer, { useMaps: true })); |
| 34 | |
| 35 | let peekVersion = bytestringToString(wbn[1]).replace(/\0+$/, ''); |
| 36 | if (!isApprovedVersion(peekVersion)) { |
| 37 | throw new Error('Unsupported web bundle version.'); |
| 38 | } |
| 39 | this.compatAdapter = this.createCompatAdapter(peekVersion); |
| 40 | |
| 41 | if (wbn.length !== this.compatAdapter.wbnLength) { |
| 42 | throw new Error( |
| 43 | `Wrong toplevel structure ${peekVersion} ${wbn.length} ${this.compatAdapter.wbnLength}` |
| 44 | ); |
| 45 | } |
| 46 | const [ |
| 47 | magic, |
| 48 | version, |
| 49 | primaryURL, // null in format version b2 |
| 50 | sectionLengthsCBOR, |
| 51 | sections, |
| 52 | length, |
| 53 | ] = this.compatAdapter.destructureBundle(wbn); |
| 54 | if (bytestringToString(magic) !== '🌐📦') { |
| 55 | throw new Error('Wrong magic'); |
| 56 | } |
| 57 | const tempVersion = bytestringToString(version).replace(/\0+$/, ''); // Strip off the '\0' paddings. |
| 58 | if (!isApprovedVersion(tempVersion)) { |
| 59 | throw new Error('Unsupported web bundle version.'); |
| 60 | } |
| 61 | this.version = tempVersion; |
| 62 | |
| 63 | if (primaryURL) { |
| 64 | this.b1PrimaryURL = asString(primaryURL); |
| 65 | } |
| 66 | const sectionLengths = asArray( |
| 67 | cborg.decode(asBytestring(sectionLengthsCBOR), { useMaps: true }) |
| 68 | ); |
| 69 | const sectionsArray = asArray(sections); |
| 70 | if (sectionLengths.length !== sectionsArray.length * 2) { |
| 71 | throw new Error( |
| 72 | "Number of elements in section-lengths and in sections don't match" |
| 73 | ); |
| 74 | } |
| 75 | for (let i = 0; i < sectionsArray.length; i++) { |
| 76 | this.sections[asString(sectionLengths[i * 2])] = sectionsArray[i]; |
| 77 | } |
| 78 | |
| 79 | if (this.sections['critical']) { |
| 80 | for (const name of asArray(this.sections['critical'])) { |
| 81 | if (!knownSections.includes(asString(name))) { |
| 82 | throw new Error(`unknown section ${name} is marked as critical`); |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | // The index section records (offset, length) of each response, but our |
| 88 | // CBOR decoder doesn't preserve location information. So, recalculate |
| 89 | // offset and length of each response here. This is inefficient, but works. |
nothing calls this directly
no test coverage detected