XMLHttpRequest not sending in Firefox (addon) - javascript

I'm developing an addon that needs to do a POST request to my server.
I'm using XMLHttpRequest for this. It's working great on Chrome, but the POST request is never sent on Firefox. Nothing is showing in the dev tools (console / network / addon inspect console), and nothing is received on my server. I've disabled any other addons and any kind of security on my whole PC (yes, I'm this desperate).
manifest.json
{
...
"manifest_version": 2,
"content_scripts": [{
"matches": ["*://myurl.com/*"],
"js": ["content.js"],
"run_at": "document_end"
}],
"permissions": ["activeTab", "webRequest"]
}
The post request in my content script
const post = () => {
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://myserver.com/test', false);
xhr.setRequestHeader('Content-Type', 'application/json');
console.log('Before sending request');
xhr.send(JSON.stringify({id: myId}));
console.log('Request sent');
return xhr.responseText;
};
Only the "Before sending request" is logged. Anything after the xhr.send() is never executed (this includes code after the post() call in the rest of my code).
My server accepts all origins. It's also correctly configured to received and process POST requests
const cors = require('cors')
app.use(cors());
What's wrong with this ? It's perfectly working on Chrome and I have no idea why it's never being sent without leaving any kind of error...

Per the post on firefox XHR working differently based on calling context consider moving the call to a background script to see if you get different behaviour.

As #Cadmium suggested in the question comments (and even though I didn't want to handle this request there), I've moved my post() function to a background script.
It's now working on both Chrome and Firefox. I still don't understand why it's behaving this way on Firefox, but it's a good enough workaround for me for now !

You should consider adding your URL (e.g. "*://myurl.com/*") as a host permission to the permission array to have privilege for XMLHttpRequest. Please see official doc here in MDN and Chrome docs.
You can see this issue was also covered in this SO answer as well
BTW, I would consider migrating to manifest V3 following this Chrome suggestion:
The Chrome Web Store no longer accepts Manifest V2 extensions. Please use Manifest V3 when building new extensions.

Related

Chrome Extension Not Sending Request [duplicate]

I've written a Chrome Extension for my library. It makes an AJAX call to api.library.edu (school's library).
My extension uses jQuery and my code looks like this:
$.get("http://api.library.edu/?period=1month", function (data) {
// process data
});
When I load my Extension, it makes the AJAX call and I get data back.
Right now I give absolutely no permissions to my extension (permissions is []).
Is my extension going to work when I publish it? Shouldn't it require special permissions to make AJAX calls with jQuery?
Thanks! I'm just making sure I wrote my extension correctly.
Your extension does not need any additional permissions to make AJAX calls from within the same origin. However, if api.library.edu does not set the proper CORS headers, you may need to request cross-origin permission for that domain:
{
"name": "My extension",
...
"permissions": [
"http://api.library.edu/"
],
...
}
From Google's Docs:
Each running extension exists within its own separate security origin. Without requesting additional privileges, the extension can use XMLHttpRequest to get resources within its installation.
...
By adding hosts or host match patterns (or both) to the permissions section of the manifest file, the extension can request access to remote servers outside of its origin.
If your extension is already working though, that would lead me to believe that the library API already has cross-domain headers set, and that you will not need any additional permissions.

Remote calls via javascript

I run a service where there is a javascript file that is called and self executed on a user's site.
This then calls an external server every 10 or so seconds with a bunch of variables.
I used to do this by using a createElement('script') and then setting the path to a file on the external server and passing the required variables across by means of GET variables. (works well for small URI's)
This worked really well and seemed to work cross browser as well with no undesired effects.
The problem I then ran into was when I needed to extend the amount or size of the variables that were being sent across. So obviously I decided to change from GET method to POST, but by doing that I could no longer use the createElement('script') trick and had to opt for the XMLHttpRequest() (ala Ajax - without jQuery) method which worked really well, except for the minor problem of having to also cater for Internet Explorer and Opera which didn't really play ball too well (big shock). So I used the following:
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("post", "http://xx.xxxx.com/");
if (request){
request.onload = function(){
//do something with request.responseText
};
request.send(myPostObjectDataVariableGoeshere);
}
..which I found over at this page
This is basically just a fallback to using the XDomainRequest() method which InternetExplorer wants you to use instead..
Fantastic, BUT -> Looking in the Console of Developer Tools in IE it says:
SEC7118: XMLHttpRequest for http://xx.xxxx.com/ required Cross Origin Resource Sharing (CORS).
SEC7120: Origin null not found in Access-Control-Allow-Origin header.
SCRIPT7002: XMLHttpRequest: Network Error 0x80070005, Access is denied.
But what's really odd about this is that I've already got the following as the first line in my backend PHP file that is being called (which works for other browsers...)
header('Access-Control-Allow-Origin: *');
Someone please tell me what's wrong here.. Also if there is a better way to be doing this instead of fighting the browser wars..
Note: I cannot use jQuery for this task!
You should try jQuery for this task. Its much easier and don't have that problem with IE.
http://api.jquery.com/jQuery.ajax/
IE unfortunately block Cross Origin requests, i believe there is no simple way to get around it by script only, but you can try tuning the options or via my proxy script.
Tuning the options
Internet Explorer ignores Access-Control-Allow headers and by default prohibits cross-origin access for Internet Zone. To enable CORS go to Tools->Internet Options->Security tab, click on “Custom Level” button. Find the Miscellaneous -> Access data sources across domains setting and select “Enable” option.
Proxy Script on local server as a Bridge
Previous post:
Remote POST request with jQuery and Ajax
This is for you to place a PHP script on a local server and do a local AJAX request and proxy to the remote server for good.

"SECURITY_ERR: DOM Exception 18" is thrown when chrome extension use "EventSrouce" is initialized

I'm using HTML5 Sever Send Event to publish some status of the server. And I'm implementing a chrome extension to track the status, and notify user if needed.
But When I'm trying to create the EventSource object
Chrome throws exception "Uncaught Error: SECURITY_ERR: DOM Exception 18"
var tracker = (function(url) {
var source = new EventSource(url);
var onMessage = function(e) {
console.log(e);
}
source.addEventListener('new', onMessage);
return {
source: source,
newMessage: onMessage
};
})('http://localhost:3000/dispatching');
And I do added the url of the server into my extension permissions:
"permissions": [
"http://localhost:3000/",
"tabs"
]
But the permission doesn't really solve the problem!
Any idea?
This looks like a Same Origin Policy issue occuring to HTML files loaded through the file:// protocol trying to contact the server via the http:// protocol.
Here is an article describing how to bypass SOP for your development environment.
When you go into production, my understanding is that that google chrome provides certain ways to by-pass the usual SOP restrictions normally imposed on browsers. This may be through the permissions JSON you mentioned however I'm not familiar enough with Chrome Extensions to say for certain.
Ah, hold on, this article might be useful.

Avoid HTTP auth popup in a chrome extension (digest)

I'm currently developing a chrome extension, I need to access some http-auth protected resources (webdav). The HTTP auth is using (in the best case) a digest authentication.
I'm able to do the auth directly in the ajax request using the https://login:password#domain.tld/path/to/ressource form.
The issue is : if the login/password is wrong, I can't just get a 401 status (unauthorized), Chrome pops up the regular authentication dialog. Which I don't want cause it's confusing for user and I can't save the credentials from here.
EDIT: Another use-case I faced is : I want to check if a resource is password-protected without trying to provide credentials to actualy access it.
Any ideas on how to catch the 401 without poping the Chrome's auth box ?
Google Chrome teams has implented the onAuthRequired event in Google Chrome 22, so now is possible detect when the HTTP Basic Authentication is required.
In fact I wrote a extension that automatically sends the HTTP Basic Authentication credentials using the onAuthRequired event.
It is available for free in the official Google Chrome web store:
https://chrome.google.com/webstore/detail/basic-authentication-auto/dgpgkkfheijbcgjklcbnokoleebmeokn
Usage example of onAuthRequired event:
sendCredentials = function(status)
{
console.log(status);
return {username: "foo", password: "bar"};
}
chrome.webRequest.onAuthRequired.addListener(sendCredentials, {urls: ["<all_urls>"]}, ["blocking"]);
You need to add the right permissions to the manifest file in order to use the onAuthRequired.
"permissions": [ "http://*/*", "https://*/*", "webRequest", "webRequestBlocking", "tabs" ],
Download the extensions and check the source code for a better approach.
It should work even if the request was initiated from another extension.
It's really seems to be a lack in chrome behavior, other people are wishing to see something as the mozBakgroundRequest Chris highlighted, there already a a bug report for that.
There are (hackish) workarounds suggested by some developers in the bugtracker :
use a webworker and a timeout to perform the request
do the same with the background page
In both case, the benefit is that it won't pop an authentication box... But you will never know if it's a real server timeout or a 401. (I didn't tested those workarounds).
I think this is impossible. If you are using the browser's http client then it will prompt the user for credentials on a 401.
EDIT : Over in mozilla land https://developer.mozilla.org/en/XMLHttpRequest check out "mozBackgroundRequest".

What permissions (if any) I need to give my Chrome Extension to let it make remote AJAX calls?

I've written a Chrome Extension for my library. It makes an AJAX call to api.library.edu (school's library).
My extension uses jQuery and my code looks like this:
$.get("http://api.library.edu/?period=1month", function (data) {
// process data
});
When I load my Extension, it makes the AJAX call and I get data back.
Right now I give absolutely no permissions to my extension (permissions is []).
Is my extension going to work when I publish it? Shouldn't it require special permissions to make AJAX calls with jQuery?
Thanks! I'm just making sure I wrote my extension correctly.
Your extension does not need any additional permissions to make AJAX calls from within the same origin. However, if api.library.edu does not set the proper CORS headers, you may need to request cross-origin permission for that domain:
{
"name": "My extension",
...
"permissions": [
"http://api.library.edu/"
],
...
}
From Google's Docs:
Each running extension exists within its own separate security origin. Without requesting additional privileges, the extension can use XMLHttpRequest to get resources within its installation.
...
By adding hosts or host match patterns (or both) to the permissions section of the manifest file, the extension can request access to remote servers outside of its origin.
If your extension is already working though, that would lead me to believe that the library API already has cross-domain headers set, and that you will not need any additional permissions.

Categories