Getting the source code of a tab from a web extension

Just a quick snippet to show how to retrieve the source code of a page from a web extension for Firefox. As a reminder, in web extensions, there are background scripts (that run as a global background process) and content scripts (that run in each tab, along with the loaded HTML pages).

Background scripts cannot directly query the source code of a page. They run in background, they do not have access to pages information. However, background and content scripts can communicate together. So, the idea is that the background script will query the source code to a content script.

Let’s start with the interesting parts of the manifest:

"background": {
  "scripts": ["path/to/background/script.js"]
},

"content_scripts": [
{
  "matches": ["<all_urls>"],
  "js": ["path/to/content/script.js"]
}
],

"permissions": ["tabs"]

Notice the tabs permission.
We need it as this is not the main messaging system. Communications between background and content scripts must go through the tab API.

Here is the content of the background script.
It queries the source code and displays it then.

// Invoke the function...
getSourceCode();

// ... defined here
function getSourceCode() {
  
  // Get the page's source code.
  // Background scripts cannot directly get it, so we ask it to our content
  // script (in the currently active tab). So we have to go through the tab API.
  browser.tabs.query({active: true, currentWindow: true}).then( tabs => {
    browser.tabs.sendMessage( tabs[0].id, {'req':'source-code'}).then( response => {
      console.log('url = ' + tabs[0].url);
      console.log('source code = ' + response.content);
    });
  });
}

As you can see, we first find the active tab.
Then, we send a request to this tab. Like all the tabs, our content script runs in it. Here is its code. It receives the query and sends the source code (within a promise).

browser.runtime.onMessage.addListener(request => {
  var response = '';
  if(request.req === 'source-code') {
    response = document.documentElement.innerHTML;
  }

  return Promise.resolve({content: response});
});

That’s it.
The web extension will be able to manipulate the source code, as an example for a deeper analysis.

Downloading a file from a Firefox’s web extension

Just a small upgrade from a previous article.
If you want your web extension to download a file from a remote location, there are only few modifications to perform.

Make sure to add the <all_urls> permission in your manifest.

"permissions": ["<all_urls>"]

And then the request will work easily.

var url = 'http://google.fr';
   
const req = new XMLHttpRequest();
// To parse the remote document directly as a DOM document
// req.responseType = "document";
 
req.onreadystatechange = function(event) {
  if (this.readyState === XMLHttpRequest.DONE) {
    if (this.status === 200) {
      console.log("Received: %s", this.responseText);
    } else {
      console.log("Error: %d (%s)", this.status, this.statusText);
    }
  }
};
 
req.open('GET', t, true);
req.send(null);

What really matters is to set the right permission in the manifest.
Otherwise, you get a 0 return code and no content.

Loading the content of a local file in Firefox’s web extensions

Since Firefox 57, browser extensions must be web extensions.
For security reasons, these API do not allow to interact with the local file system. There are several strategies described on the web site as alternatives (the IndexedDB being one of the most interesting one IMO).

In this article, I will only describe how one of your script can load a local resource that was put within your extension. I used it to load a XML file in a background script.

First, make sure you make your resource available for web access.
Add this in your manifest:

"web_accessible_resources": ["path/to/my-resource.xml"],

And then, in your script:

var localUrl = browser.extension.getURL('path/to/my-resource.xml');
  
const req = new XMLHttpRequest();
// To parse the remote document directly as a DOM document
// req.responseType = "document";

req.onreadystatechange = function(event) {
  if (this.readyState === XMLHttpRequest.DONE) {
    if (this.status === 200) {
      console.log("Received: %s", this.responseText);
    } else {
      console.log("Error: %d (%s)", this.status, this.statusText);
    }
  }
};

req.open('GET', t, true);
req.send(null);

And that’s it.
This snippet will only print the file’s content, but you can adapt it for you needs.

Increase Import File Size in Test Link

Just a quick reminder post…
By default, Test Link comes with a limit of 400 KB to import tests specifications. To raise this limit, there are two files to update.

The first one is the php.ini file.
On Linux, you can find its location with the php --ini command. Find the upload_max_filesize parameter and increase its size. This is a global PHP setting.

You then need to update the configuration of TestLink.
Find the config.inc.php file and change the $tlCfg->import_file_max_size_bytes parameter.

You might want to update the $tlCfg->import_max_row and $tlCfg->repository_max_filesize settings too.

I personally run it with Docker Compose (Test Link 1.19.x).
Here are the values I use:

  • upload_max_filesize (php.ini): 20 MB
  • $tlCfg->import_file_max_size_bytes (config.inc.php): 8192000
  • $tlCfg->import_max_row (config.inc.php): 100000
  • $tlCfg->repository_max_filesize (config.inc.php): 8 // MB