7

I try to write an extension caching some large media files used on my website so you can locally cache those files when the extension is installed:

  1. I pass the URLs via chrome.runtime.sendMessage to the extension (works)
  2. fetch the media file via XMLHttpRequest in the background page (works)
  3. store the file using FileSystem API (works)
  4. get a File object and convert it to a URL using URL.createObjectURL (works)
  5. return the URL to the webpage (error)

Unfortunately the URL can not be used on the webpage. I get the following error:

Not allowed to load local resource: blob:chrome-extension%3A//hlcoamoijhlmhjjxxxbl/e66a4ebc-1787-47e9-aaaa-f4236b710bda

What is the best way to pass a large file object from an extension to the webpage?

tom_ma
  • 618
  • 1
  • 6
  • 9
  • in chrome, you can use postMessage() to pass transferable objects between different browsing contexts. – dandavis May 24 '14 at 17:25
  • 1
    runtime.postMessage() seems to be different to window.postMessage() since it seems to always use JSON and it has no transfer parameter. I do not know the window object of the website requesting the file from the extension. – tom_ma May 24 '14 at 17:48

2 Answers2

11

You're almost there.

After creating the blob:-URL on the background page and passing it to the content script, don't forward it to the web page. Instead, retrieve the blob using XMLHttpRequest, create a new blob:-URL, then send it to the web page.

// assuming that you've got a valid blob:chrome-extension-URL...
var blobchromeextensionurlhere = 'blob:chrome-extension....';
var x = new XMLHttpRequest();
x.open('GET', blobchromeextensionurlhere);
x.responseType = 'blob';
x.onload = function() {
    var url = URL.createObjectURL(x.response);
    // Example: blob:http%3A//example.com/17e9d36c-f5cd-48e6-b6b9-589890de1d23
    // Now pass url to the page, e.g. using postMessage
};
x.send();

If your current setup does not use content scripts, but e.g. the webRequest API to redirect request to the cached result, then another option is to use data-URIs (a File or Blob can be converted to a data-URI using <FileReader>.readAsDataURL. Data-URIs cannot be read using XMLHttpRequest, but this will be possible in future versions of Chrome (http://crbug.com/308768).

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • looks like this was just broken in chromium with this fix, see: https://chromium-review.googlesource.com/c/chromium/src/+/962975 – artfulhacker Mar 23 '18 at 06:40
  • @artfulhacker I filed a bug report at https://bugs.chromium.org/p/chromium/issues/detail?id=825296 . – Rob W Mar 23 '18 at 18:54
  • should we merge it into this one? https://bugs.chromium.org/p/chromium/issues/detail?id=825111 I should have mentioned I filed one too – artfulhacker Mar 24 '18 at 21:32
0

Two possibilities I can think of.

1) Employ externally_connectable.

This method is described in the docs here.

The essence of it: you can declare that such and such webpage can pass messages to your extension, and then chrome.runtime.connect and chrome.runtime.sendMessage will be exposed to the webpage.

You can then probably make the webpage open a port to your extension and use it for data. Note that only the webpage can initiate the connection.

2) Use window.PostMessage.

The method is mentioned in the docs (note the obsolete mention of window.webkitPostMessage) and described in more detail here.

You can, as far as I can tell from documentation of the method (from various places), pass any object with it, including blobs.

Xan
  • 74,770
  • 16
  • 179
  • 206
  • thanks for the answer. actually 1) is the thing i tried but the blob is not usable outside of the background page. unfortunately i do know how to find the window object of the page from the background page to employ 2) – tom_ma May 24 '14 at 18:49
  • You need a content script for 2) – Xan May 24 '14 at 18:49
  • but the content script wouldn't have the unlimitedStorage i need for caching which seems to be limited to the background script. at least not in my tests. – tom_ma May 24 '14 at 18:50
  • Content scripts must communicate with the background using messaging to pass data, yes. – Xan May 24 '14 at 18:55