Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome Extension - Getting "tab was closed" error on injecting a script

I am writing a chrome extension which detects the type of file being opened and based on that injects a script on the page which does many other things. Here is the part of my code for the background.js which is injecting the script:

chrome.webRequest.onHeadersReceived.addListener(function(details){
        console.log("Here: " + details.url + " Tab ID: " + details.tabId);
        if(toInject(details))
        {   
            console.log("PDF Detected: " + details.url);
            if(some-condition) 
            {
                //some code
            }
            else
            {
                chrome.tabs.executeScript(details.tabId, { file: "contentscript.js", runAt: "document_start"}, function(result){
                    if(chrome.runtime.lastError)
                    {
                        console.log(chrome.runtime.lastError.message + " Tab ID: " + details.tabId);
                    }
                });
            }
            return {
            responseHeaders: [{
              name: 'X-Content-Type-Options', 
              value: 'nosniff'
            }, 
                {
              name: 'X-Frame-Options', 
                /*
                    Deny rendering of the obtained data.
                    Cant use {cancel:true} as we still need the frame to be accessible.
                */
              value: 'deny'
            }]
          };
        }
}, {
    urls: ['*://*/*'],
    types: ['main_frame', 'sub_frame']
}, ['blocking', 'responseHeaders']);

Here is the manifest file:

{
    "manifest_version": 2,

    "name": "ABCD",
    "description": "ABCD",
    "version": "1.2",

    "icons": {
        "16" :  "images/16.png",
        "32" :  "images/32.png",
        "48" :  "images/48.png",
        "128" :  "images/128.png"
    },

    "background": {
        "scripts": ["chrome.tabs.executeScriptInFrame.js", "background.js"],
        "persistent": true
    },

    "permissions": [
        "webRequest",
        "<all_urls>",
        "webRequestBlocking",
        "tabs",
        "nativeMessaging"
    ],
    "web_accessible_resources": [ "getFrameId", "aux.html", "chrome-extension:/*", "images/*.png", "images/*.gif", "style.css"]
}

The problem is that when injecting script the last error part runs and it shows the tab was closed and the script is not injected. If I press enter on the omnibox a several times the script is injected and things work fine. Here is a sample run of events:

Sample output on console

Sorry for my naive photo editing :P

There are a few more things we can deduce from this image:

  1. The first thing being loaded in the tab with tab id 86 is something related to my google account. I have logged out and also turned off the prerender feature of chrome.
  2. On pressing enter several times the tab was closed error goes but the script which maintains a chrome.runtime connection with the background.js gets disconnected.
  3. And then finally things work fine.

I have been banging my head around this for days. No other question on SO addresses this problem. Nor anywhere else on the internet as well.

EDIT:

One more thing to note: The sample run shown in the image above is one such. There are many different behaviors. Sometimes 3 enters wouldn't make it work. Sometimes just one will. Is there something wrong because of the custom headers i am sending?

UPDATE #1

One must notice the headers I am returning in OnHeadersReceived. It's being done to stop chrome from rendering the document. But on doing that all the data of the file is dumped on the screen and I don't want that to appear. So i think I need document_start so that I can hide the dumped data before my content script does other things like putting a custom UI on the page.

UPDATE #2

Noticed one more thing. If I open a new tab, and then paste a url there and then press enter the following is the output of the background page on the console.

Sample output number 2

So I guess, the location of the window is updated at a later time by chrome. Am I right? Any workarounds?

like image 240
tapananand Avatar asked Nov 26 '15 12:11

tapananand


1 Answers

"The tab was closed" error message is a bit misleading, because the tab obviously is not closed. In chrome sources the variable with the string is called kRendererDestroyed. So the error is because the corresponding renderer is being destroyed for some reason.

I was getting the error if the the page opened in tab redirected (thus one renderer destroyed, another one created for the same tab, but different url this time), in this case extension will got tab updates with statuses like:

  • loading url: 'example.com', here tab is already returned to callbacks etc, but will get the error, if tried to inject script
  • loading url: 'example.com/other_url'
  • title: 'some title'
  • complete

I managed to get around by injecting script only after receiving status: 'complete' (but probably injecting on title should also do)

Did not try with pdfs, but chrome probably will replace renderer for those too like with a redirect. So look more into page statuses and redirects/renderer replaces. Hope this helps anyone stumbling upon this question.

like image 173
Vasfed Avatar answered Sep 18 '22 05:09

Vasfed