Skip to content

Commit

Permalink
Strict content-type checks (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Aug 29, 2019
1 parent f701d2f commit 58074e6
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 37 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ importShim('/path/to/module.js').then(x => console.log(x));

### JSON Modules

To load [JSON Modules](https://github.com/whatwg/html/pull/4407), import any file with a `.json` file extension:
To load [JSON Modules](https://github.com/whatwg/html/pull/4407), import any JSON file served with `application/json`:

```js
import json from './test.json';
```

### CSS Modules

To load [CSS Modules](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/css-modules-v1-explainer.md), import any file with a `.css` file extension:
To load [CSS Modules](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/css-modules-v1-explainer.md), import any file with served with `text/css`:

```js
import css from './style.css';
Expand All @@ -92,7 +92,7 @@ For other browsers a [polyfill](https://github.com/calebdwilliams/construct-styl

### Web Assembly

To load [Web Assembly Modules](https://github.com/webassembly/esm-integration), import a module with a `.wasm` file extension:
To load [Web Assembly Modules](https://github.com/webassembly/esm-integration), import a module served with `application/wasm`:

```js
import { fn } from './test.wasm';
Expand All @@ -102,6 +102,8 @@ Web Assembly imports are in turn supported.

Import map support is provided both for mapping into Web Assembly URLs, as well as mapping import specifiers to JS or WebAssembly from within WASM.

> Note some servers don't yet support serving `.wasm` files as `application/wasm` by default, in which case an invalid content type error will be thrown. The `application/wasm` MIME type is necessary for loading Web Assembly in line with the specification for browser modules.
### Module Workers

To load workers with full import shims support, the `WorkerShim` constructor can be used:
Expand Down
75 changes: 42 additions & 33 deletions src/es-module-shims.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,42 +172,51 @@ function getOrCreateLoad (url, source) {

load.r = res.url;

if (res.url.endsWith('.wasm')) {
const module = wasmModules[url] = await (WebAssembly.compileStreaming ? WebAssembly.compileStreaming(res) : WebAssembly.compile(await res.arrayBuffer()));
const contentType = res.headers.get('content-type');
const semicolonIndex = contentType.indexOf(';');
const mime = semicolonIndex === -1 ? contentType : contentType.slice(0, semicolonIndex);
switch (mime) {
case 'application/wasm':
const module = wasmModules[url] = await (WebAssembly.compileStreaming ? WebAssembly.compileStreaming(res) : WebAssembly.compile(await res.arrayBuffer()));

let deps = WebAssembly.Module.imports ? WebAssembly.Module.imports(module).map(impt => impt.module) : [];
let deps = WebAssembly.Module.imports ? WebAssembly.Module.imports(module).map(impt => impt.module) : [];

const aDeps = [];
load.a = [aDeps, WebAssembly.Module.exports(module).map(expt => expt.name)];

const depStrs = deps.map(dep => JSON.stringify(dep));

let curIndex = 0;
load.S = depStrs.map((depStr, idx) => {
const index = idx.toString();
const strStart = curIndex + 17 + index.length;
const strEnd = strStart + depStr.length - 2;
aDeps.push({
s: strStart,
e: strEnd,
d: -1
});
curIndex += strEnd + 3;
return `import*as m${index} from${depStr};`
}).join('') +
`const module=importShim.w[${JSON.stringify(url)}],exports=new WebAssembly.Instance(module,{` +
depStrs.map((depStr, idx) => `${depStr}:m${idx},`).join('') +
`}).exports;` +
load.a[1].map(name => name === 'default' ? `export default exports.${name}` : `export const ${name}=exports.${name}`).join(';');
return deps;

const aDeps = [];
load.a = [aDeps, WebAssembly.Module.exports(module).map(expt => expt.name)];

const depStrs = deps.map(dep => JSON.stringify(dep));

let curIndex = 0;
load.S = depStrs.map((depStr, idx) => {
const index = idx.toString();
const strStart = curIndex + 17 + index.length;
const strEnd = strStart + depStr.length - 2;
aDeps.push({
s: strStart,
e: strEnd,
d: -1
});
curIndex += strEnd + 3;
return `import*as m${index} from${depStr};`
}).join('') +
`const module=importShim.w[${JSON.stringify(url)}],exports=new WebAssembly.Instance(module,{` +
depStrs.map((depStr, idx) => `${depStr}:m${idx},`).join('') +
`}).exports;` +
load.a[1].map(name => name === 'default' ? `export default exports.${name}` : `export const ${name}=exports.${name}`).join(';');

return deps;
case 'application/json':
source = `export default JSON.parse(${JSON.stringify(await res.text())})`;
break;
case 'text/css':
source = `const s=new CSSStyleSheet();s.replaceSync(${JSON.stringify(await res.text())});export default s`;
break;
case 'application/javascript':
source = await res.text();
break;
default:
throw new Error(`Unknown Content-Type "${contentType}"`);
}

source = await res.text();
if (res.url.endsWith('.json'))
source = `export default JSON.parse(${JSON.stringify(source)})`;
if (res.url.endsWith('.css'))
source = `const s=new CSSStyleSheet();s.replaceSync(${JSON.stringify(source)});export default s`;
}
try {
load.a = parse(source, load.u);
Expand Down
2 changes: 1 addition & 1 deletion test/browser-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ suite('Basic loading tests', () => {
});

test('Should import a module via data url', async function () {
var m = await importShim('data:text/plain;charset=utf-8;base64,ZXhwb3J0IHZhciBhc2RmID0gJ2FzZGYnOw0KZXhwb3J0IHZhciBvYmogPSB7fTs=');
var m = await importShim('data:application/javascript;charset=utf-8;base64,ZXhwb3J0IHZhciBhc2RmID0gJ2FzZGYnOw0KZXhwb3J0IHZhciBvYmogPSB7fTs=');
assert(m);
assert.equal(m.asdf, 'asdf');
});
Expand Down

0 comments on commit 58074e6

Please sign in to comment.