Skip to content

Commit

Permalink
Experiment with staticFetch to improve reliability of large data: URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
GarboMuffin committed Jan 9, 2024
1 parent e4e461a commit 088b0c1
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/extension-support/tw-unsandboxed-extension-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const ScratchCommon = require('./tw-extension-api-common');
const createScratchX = require('./tw-scratchx-compatibility-layer');
const AsyncLimiter = require('../util/async-limiter');
const createTranslate = require('./tw-l10n');
const staticFetch = require('../util/tw-static-fetch');

/* eslint-disable require-await */

Expand Down Expand Up @@ -97,6 +98,12 @@ const setupUnsandboxedExtensionAPI = vm => new Promise(resolve => {

Scratch.fetch = async (url, options) => {
const actualURL = url instanceof Request ? url.url : url;

const staticFetchResult = staticFetch(url);
if (staticFetchResult) {
return staticFetchResult;
}

if (!await Scratch.canFetch(actualURL)) {
throw new Error(`Permission to fetch ${actualURL} rejected.`);
}
Expand Down
36 changes: 36 additions & 0 deletions src/util/tw-static-fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @fileoverview
* The new URL() and fetch() provided by the browser tend to buckle when dealing with URLs that are
* tens of megabytes in length, which can be common when working with data: URLs in extensions.
*
* To help avoid that, this file can "statically" parse some data: URLs without going through
* unreliable browser APIs.
*/

const Base64Util = require('./base64-util');

/**
* @param {string} url
* @returns {Response|null}
*/
const staticFetch = url => {
try {
const simpleDataUrlMatch = url.match(/^data:([/-\w\d]*);base64,/i);
if (simpleDataUrlMatch) {
const contentType = simpleDataUrlMatch[1].toLowerCase();
const base64 = url.substring(simpleDataUrlMatch[0].length);
const decoded = Base64Util.base64ToUint8Array(base64);
return new Response(decoded, {
headers: {
'content-type': contentType,
'content-length': decoded.byteLength
}
});
}
} catch (e) {
// not robust enough yet to care about these errors
}
return null;
};

module.exports = staticFetch;
38 changes: 38 additions & 0 deletions test/unit/tw_static_fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const {test} = require('tap');
const staticFetch = require('../../src/util/tw-static-fetch');

test('fetch simple base64', t => {
const res = staticFetch('data:text/plain;base64,VGVzdGluZyB0ZXN0aW5nIDEyMw==');
res.text().then(text => {
t.equal(text, 'Testing testing 123');
t.equal(res.status, 200);
t.equal(res.ok, true);
t.equal(res.headers.get('content-type'), 'text/plain');
t.equal(res.headers.get('content-length'), '19');
t.end();
});
});

test('fetch base64 with all possible bytes', t => {
// eslint-disable-next-line max-len
const res = staticFetch('Data:Application/Octet-Stream;BASE64,AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==');
res.arrayBuffer().then(buffer => {
t.same(Array.from(new Uint8Array(buffer)), Array(256)
.fill()
.map((_, index) => index)
);
t.equal(res.headers.get('content-type'), 'application/octet-stream');
t.equal(res.headers.get('content-length'), '256');
t.end();
});
});

test('fetch not data:', t => {
t.equal(staticFetch('blob:https://turbowarp.org/54346944-16cf-4ce9-aed4-e1df8ad0d779'), null);
t.equal(staticFetch('https://example.com/'), null);
t.equal(staticFetch('http://example.com/'), null);
t.equal(staticFetch('file:///etc/hosts'), null);
t.equal(staticFetch('oegirjdf'), null);
t.equal(staticFetch(''), null);
t.end();
});

0 comments on commit 088b0c1

Please sign in to comment.