XMLHttpRequest problem in Firefox extension I'm developing

I’m developing a Firefox extension that asks the user for credentials, and I’m facing a strange problem. Depending on where in the code I place the .send call, the code performs the network request or not.

Here is the manifest.json (the hostname and domain have been replaced by a fake one):

{
  "applications": {
    "gecko": {
      "id": "extension@example.com",
      "strict_min_version": "58.0a1"
    }
  },
  "browser_action": {
    "browser_style": true,
    "default_title": "Title",
    "default_popup": "mowl.html"
  },
  "description": "Description",
  "homepage_url": "https://example.com",
  "manifest_version": 2,
  "name": "Name",
  "permissions": [
    "*://www.example.com/*",
    "tabs"
  ],
  "content_security_policy": "script-src 'self' https://www.example.com; object-src 'self'",
  "version": "1.0"
}

This is the HTML popup file:

<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8">
<script src="mowl.js"></script>
</head>

<body>
  Please login: <br><br>
  <input type='email' placeholder='Email address:'' name='email' id='email' size='50'><br><br>
  <input type='password' placeholder='Password' name='password' id='password' size='50'><br><br>
  <button id="signin">Ok</button>
</body>

</html>

And finally, the javascript code:

function processlogin() {
  console.log('in processlogin');
  if(http.readyState == 4) {
      console.log(http.readyState);
  }
}

function buttonClicked() {
   document.querySelector('#signin').addEventListener('click', dologin, false);
}

function dologin () {
  console.log('in dologin');
  var website = "https://www.example.com/signin.php";
  var params = "email=" + document.getElementById('email').value + "&password=" + document.getElementById('password').value;
  http.open("POST", website);
  http.responseType = 'text';
  http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  http.onreadystatechange = processlogin;
  http.send(params);
}

document.addEventListener("DOMContentLoaded", buttonClicked);
var http = new XMLHttpRequest();

Testing that code in Firefox with the debugger shows that not network request is performed at all when the button is clicked. I’ve placed console.log statements in different places to verify that the different functions are called when expected.

But, modifying the javascript this way:

function processlogin() {
  console.log('in processlogin');
  if(http.readyState == 4) {
      console.log(http.readyState);
  }
}

function buttonClicked() {
   document.querySelector('#signin').addEventListener('click', dologin, false);
}

function dologin () {
  console.log('in dologin');
}

document.addEventListener("DOMContentLoaded", buttonClicked);
var http = new XMLHttpRequest();
var website = "https://www.example.com/signin.php";
var params = "email=" + document.getElementById('email').value + "&password=" + document.getElementById('password').value;
http.open("POST", website);
http.responseType = 'text';
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.onreadystatechange = processlogin;
http.send(params);

makes the network call being performed (obviously without having to click on the button) and reported in the Firefox debugger. I don’t understand what is happening.

Someone can please provide me some guidance on what I’m doing wrong with this?

Thanks a lot!

In your last code you are making a request outside any function (in the top level execution), so it’s executed when JavaScript file is processed.

Regardless I would change two things in your code.

  1. I would switch to asynchronous fetch API - it’s much easier to reason about and it makes the code easier to understand
  2. you should NEVER send sensitive information in the URL. You should send the password and e-mail as body or in the headers.

A note regarding your manifest file. Do not modify the default values of the key content_security_policy. Doing so will most likely get you rejected once you submit your add-on to AMO.

They are sent as body, they are just sent URL encoded (manually, and not actually encoded)

Oh my bad :slight_smile:. I got confused.

Hi juraj.masiar

Thanks for your answer.

It is clear that in the second version of the js code the request is made outside any function. I was just trying to show the strange issue I’m facing: network request works outside the function but not inside it.

I’ve modified the code to use fetch, but the behavior is exactly the same: fetch outside the function performs the network request, but not inside the function.

So, it is not about using fetch or xmlhttprequest, but about some kind of restriction or similar that I’m not aware about.

Thanks anyway for the proposal.

Thanks for the heads up about that.

The most likely cases from the outsides is that there is some error that only happens when you test it with pushing the button. That could be the request being malformed etc. Since you insist that dologin is called, it must be something that comes after that logging statement that is failing. A powerful way to find out would be to use the debugger and step through, or at least pause on network requests and any exceptions.

Since the button is not in a form I don’t think the page would be reloading, when you click it, right? I also noticed that your HTML may be invalid with things like two '' after the placeholder for the email input.

Hey Martin,

The double ’ was just a copy&paste typo: it is not in the real code. Anyway thanks for noticing it: you never know…

Turns out that the network requests ARE being done no matter if the code is inside or outside a function. BUT for whatever the reason, Firefox debugger is NOT showing the network calls when they are inside a function!!! or maybe the output is cleared before being able to be seen, who knows…

I managed to have access to the backend side of the application, and there I was able to see the network requests being received, and also to fix the code so the extension now is working as expected.

Cheers

That sounds like the button is actually inside a <form> and submitting it, leading to Firefox reloading the page. Try checking “persist logs” so you will see it, and make the button type="button" or do the request in the form submit event and prevent that instead. Using the submit event also means that Enter will work to submit the form.

The network calls are shown only in the “correct” debugging window. So if you are doing requests from background script, they will appear in the debugging window of your background script. Request made from content script or pop-up or custom add-on page are also logged only in their debugging windows. Make sure you are checking the correct one!

This is different compare to normal console logs that are (always?) aggregated to the main background script debugging console.

See how to debug pop-up: