4

I want to pass the input file from content page to extension background script, and then load it with FileReader() in the extension background script.

So in the web page I have a <input type="file"> and from onchange event I pass the file from content script to background page like this:

 var myfile = document.getElementById('fileid').files[0];
 chrome.runtime.sendMessage({myevent: "start", inputfile: myfile}, function(response) {});

in the background script I have this:

chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){

   if(message.myevent==="start")
   {
      var reader = new FileReader();

         reader.onload = function(e) {
              // file is loaded 
         }  


       reader.readAsArrayBuffer(message.inputfile);
   }
});

but FileReader not load it, I'm not sure if this is correct way , but all i need is to pass the input file element to background script and load it with FileReader to send it with HTTP POST from background script. Please tell me what is wrong or how to do it correctly. It will help a lot if I see a sample code, because I'm new to chrome extension development, and not so experienced.

Jigberto
  • 1,513
  • 7
  • 27
  • 50

2 Answers2

3

All messages send through the Chrome extension messaging API MUST be JSON-serializable. If you want to get the contents of a file at the background page, you'd better create a (temporary) URL for the File object, pass this URL to the background page and use XMLHttpRequest to grab its contents:

// Create URL
var url = URL.createObjectURL(myfile);
// Pass URL to background page (ommited for brevity) and load it..
var x = new XMLHttpRequest();
x.onload = function() {
     var result = x.response;
     // TODO: Use [object ArrayBuffer]
};
x.open('GET', url); // <-- blob:-url created in content script
x.responseType = 'arraybuffer';
x.send();

Though why do you want to send the file to the background page? Content scripts can also send cross-origin requests.

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • that make sens, i will check that and get back to you, i have upvoted your answers as it looks nice and it is something new for me, I will more than happy to see your solution working for me, and I would accept it. thanks – Jigberto Jun 13 '14 at 10:15
  • I have accepted your answer. that work fine if file has a small size, but if file size is 200 Mb then extension will crash. what i try to do is to create multipart HTTP POST and upload a big file. Do you have any suggestions for that ? – Jigberto Jun 13 '14 at 14:41
  • @Jigberto Crashing sounds like a bug. Could you provide source code with a minimal example and provide the steps-to-reproduce at http://crbug.com/new? I can also report the bug for you if desired. – Rob W Jun 13 '14 at 17:00
  • thank you for your support, i have opened a separate question for that, please check the link, I hope you can help me. thanks. http://stackoverflow.com/questions/24211073/chrome-extension-crashes-when-i-try-to-upload-a-big-file – Jigberto Jun 13 '14 at 17:46
  • Hi Rob, 6 years on, would this still be the easiest way to achieve file transfer from content script to the background page? Are there any easy alternatives (some new APIs) in 2020? This question has become more important since content scripts don't allow cross-origin requests anymore. – Armand May 24 '20 at 14:11
  • 2
    @Armand In Chrome, there is still not an easy/convenient way to send files to the background. Since the answer has been written, web-accessible extension frames have access to the same kind of APIs as the background page, so these could be used instead together with DOM's postMessage to send the file. This is however more complicated... Firefox does support [structured cloning](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) in its extension messaging API, which allows you to directly send a File/Blob to the background, which makes it much easier. – Rob W Jun 01 '20 at 21:24
  • Worked fine for me in chrome, but this approach has origin issues in Firefox, probably because the content scirpt runs in the page context and the background script in extension context. Some people seem to have issues in chrome too: https://stackoverflow.com/questions/51082976/can-chrome-content-and-background-scripts-share-access-to-blob-urls – mxt3 Dec 31 '20 at 12:09
  • As of 2020, Content Scripts are unable to send Cross Origin requests: https://www.chromium.org/Home/chromium-security/extension-content-script-fetches/ – Nick Q. Feb 06 '23 at 21:55
0

This works for chrome. You could find the whole production code here.

https://github.com/Leslie-Wong-H/BoostPic/tree/7513b3b8d67fc6f57718dc8b9ff1d5646ad03c75/BoostPic_Chrome/js

main.js:


    // Crossbrowser support for URL
    const URLObj = window.URL || webkitURL;

    // Creates a DOMString containing a URL representing the object given in the parameter
    // namely the original Blob
    const blobUrl = URLObj.createObjectURL(imageBlob);
    console.log(blobUrl);
    chrome.runtime.sendMessage(blobUrl, (res) => {
      imgUrl = res;
      console.log(imgUrl);
      clearInterval(refreshIntervalId);
      // To prevent that it happens to halt at "  Image uploading ..."
      setTimeout(() => {
        var imgUrlText = document.querySelector(imgUrlTextBoxId);
        imgUrlText.value = imgUrl;
      }, 1000);
      // double check to clear interval to prevent infinite error loop of LoadingStateOne
      // Hope it works.
      setTimeout(() => {
        clearInterval(refreshIntervalId);
      }, 500);
      console.log("Stop uploading state message");

background.js:


chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.startsWith("blob")) {
    console.log("RECEIVED");
    getBase64Url(request).then((res) => {
      console.log("Arrived here");
      // Acquired from https://stackoverflow.com/questions/18650168/convert-blob-to-base64/18650249#
      const reader = new FileReader();
      reader.readAsDataURL(res);
      reader.onloadend = function () {
        const base64data = reader.result;
        console.log(base64data);
Leslie Wong
  • 109
  • 1
  • 6