I want to send an array from my content script to the background page, so that it can be stored and called upon later from the popup using chrome.extension.getBackgroundPage().
At the moment, my background page looks like this (based on an example from the developer website).
<html>
<head>
<script>
function onRequest(request, sender, sendResponse) {
chrome.pageAction.show(sender.tab.id);
sendResponse({});
};
chrome.extension.onRequest.addListener(onRequest);
</script>
</head>
</html>
My content script performs a few simple regexes, and if it finds a match responds with:
chrome.extension.sendRequest({}, function(response) {});
What I would like to do is send an array created by the content script back to the background page. I'm somewhat stumped as to how to go about this. Do I need to create a second request, or can I send the array along with the response above.
Thank you all for your help. This is my first time posting here, though I've long benefited from the questions and answers posted by others :)
Assuming your array of matches is called matches, your content script could use something like:
chrome.extension.sendRequest({matches: matches}, function(response) {});
Then in your background page, you can extract the matches array from the request:
function onRequest(request, sender, sendResponse) {
var matches = request.matches;
// do stuff with the matches array here
sendResponse({});
};
Generally, whatever data you put into the request argument of chrome.extension.sendRequest will be passed to your onRequest function. See the extension documentation about message passing for more details.
Related
I am currently writing a userscript for website A to access another the contents on website B. So I tried to use the GM_xmlhttpRequest to do it. However, a variable on B is written to the window property eg: window.var or responseContent.var.
However, when I tried to get the window.var, the output is undefined, which means the properties under the window variable cannot be read successfully. I guess the window object is refering to the website A but not website B, so the result is undefined (There is no window.var on A).
I am sure that the GM_xmlhttpRequest has successfully read the content of the website B because I have added console.log to see the response.responseText. I have also used the window.var to successfully visit that variable on website B by browser directly.
GM_xmlhttpRequest({
method: "GET",
url: url,
headers: {
referrer: "https://A.com"
},
onload: function (response) {
// console.log(response.responseText);
let responseContent = new Document();
responseContent = new DOMParser().parseFromString(response.responseText, "text/html");
let titleDiv = responseContent.querySelector("title");
if (titleDiv != null) {
if (titleDiv.innerText.includes("404")) {
console.log("404");
return;
} else {
console.log(responseContent.var);
console.log(window.var);
}
}
},
onerror: function (e) {
console.log(e);
}
});
I would like to retrieve content window.var on website B and show it on the console.log of A
Please help me solve the problem. Thank you in advance.
#wOxxOm's comments are on point. You cannot really get the executed javascript of another website like that. One way to go around it is to use <iframe> and post message, just like #wOxxOm said. But that may fail if the other website has policy against iframes.
If this userscript is just for your use, another way is to have two scripts, one for each website and have them both open in browser tabs. Then again you can use postMessage to have those two scripts communicate the information. Dirty solution for your second userscript would be to just post the variable info on regular interval:
// Userscript for website-b.com
// needs #grant for unsafe-window to get the window.var
setInterval(()=>{postMessage(unsafeWindow.var, "website-a.com");}, 1000);
That would send an update of var's value every second. It's not very elegant, but it's simple and works. For a more elegant solution, you may want to first postMessage from website a that will trigger postMessage(unsafeWindow.var, "website-a.com"). Working with that further, you will soon find yourself inventing an asynchronous communication protocol.
Alternatively, if the second website is simple, you can try to parse the value of var directly from HTML, or wherever the value is coming from. That's a preferred solution, but requires reverse-engineering on your part.
As the title says, I'm trying to intercept script requests from the user's page, make a GET request to the script url from the background, add a bit of functionality and send it back to the user.
A few caveats:
I don't want to do this with every script request
I still have to guarantee that the script tags are executed in the original order
So far I came with two solutions, none of which work properly. The basic code:
chrome.webRequest.onBeforeRequest.addListener(
function handleRequest(request) {
// First I make the get request for the script myself SYNCHRONOUSLY,
// because the webRequest API cannot handle async.
const syncRequest = new XMLHttpRequest();
syncRequest.open('GET', request.url, false);
syncRequest.send(null);
const code = syncRequest.responseText;
},
{ urls: ['<all_urls>'] },
['blocking'],
);
Now once we have the code, there are two approaches that I've tried to insert it back into the page.
I send the code through a port to a content script, that will add it to the page inside a <script></script> tag. Along with the code, I also send an index to keep sure the scripts are inserted back into the page in the correct order. This works fine for my dummy website, but it breaks on bigger apps, like youtube, where it fails to load the image of most videos. Any tips on why this happens?
I return a redirect to a data url:
if (condition) return { cancel: false }
else return { redirectUrl: 'data:application/javascript; charset=utf-8,'.concat(alteredCode) };
This second options breaks the code formatting, sometimes removing the space, sometimes cutting it short. I'm not sure on the reason behind this behavior, it might have something to do with data url spec.
I'm stuck. I've researched pretty much every related answer on this website and couldn't find anything. Any help or information is greatly appreciated!
Thanks for your time!!!
Im making a small google chrome extension that is watching all calls a page is making. The idea is to log how a page behaves and how many external calls are made. Got everything working except the part where i need to get the source url of the page that initiates the call.
For example im going to www.stackoverflow.com in my browser, then my onbeforerequest lister kicks in and gives me all the calls. So far so good. But i still want the name of the page which is making the calls, in this case i want: "www.stackoverflow.com" and the owner of the calls.
I tried getting it from the tabs, but chrome.tabs.get uses a callback and that is not called before its all over and i got all the calls processed.
any ideas on how to get the source url?
edit
Im using this code right now, to get the url, but it keeps returning "undefined":
var contentString = "";
chrome.webRequest.onBeforeRequest.addListener(
function (details) {
var tabid = details.tabId;
var sourceurl = "N/A";
if (tabid >= 0) {
chrome.tabs.get(parseInt(tabid), function (tab) {
sourceurl = tab.url;
alert(sourceurl);
});
}
});
When doing the alert, i get undefined for every request
edit 2 - this is working for me
chrome.tabs.get(parseInt(tabid), function (tab) {
if (tab != undefined) {
alert(tab.url);
}
});
onBeforeRequest returns a TabID, then you can then use the get method of the tabs API to get a reference to the tab and thus the URL of the page.
You can use the details.initiator (see here for more details) which is supported since Chrome 63 version. Below you can see what is mentioned on Chrome APIs page about the initiator.
The origin where the request was initiated. This does not change
through redirects. If this is an opaque origin, the string 'null' will
be used.
In my extension I need to transfer some data from one tab's content script to another tab's content script. How can I choose certain tab using chrome.tabs, if I know a part of that tab object's name or url in it? How can two tabs' scripts communicate?
UPDATE:
Apparently I don't have method sendMessage in chrome.extension. When I run the following from content script:
chrome.extension.sendMessage("message");
I get in console:
Uncaught TypeError: Object # has no method 'sendMessage'
First, note that messages passed within an extension are JSON-serialized. Non-serializable types, such as functions, are not included in the message.
Within a content script, you have to pass the message to the background page, because there is no method to directly access other tabs.
// Example: Send a string. Often, you send an object, which includes
// additional information, eg {method:'userdefined', data:'thevalue'}
chrome.extension.sendMessage(' ... message ... ');
In the background page, use the chrome.tabs.query method to get the ID of a tab. For the simplicity of the example, I've hardcoded the patterns and urls. It might be a good idea to include the query values from the previous message, in this way: {query:{...}, data:...}.
// background script:
chrome.extension.onMessage.addListener(function(details) {
chrome.tabs.query({
title: "title pattern",
url: "http://domain/*urlpattern*"
}, function(result) {
// result is an array of tab.Tabs
if (result.length === 1) { // There's exactely one tab matching the query.
var tab = result[0];
// details.message holds the original message
chrome.tabs.sendMessage(tab.id, details.message);
}
});
});
chrome.tabs.sendMessage was used to pass the original data to a different tab.
Remark: In the example, I only passed the message when the query resulted in one unique tab. When uniqueness is not a prerequisite, just loop through all resulting tabs, using result.forEach or:
for (var i=0, tab; i<result.length; i++) {
tab = results[i];
...
}
From a content script you only can communicate with the background process.
You may communicate between two content scripts in differents tabs using the backgound as intermediate.
Also the DOM provide other way to communicate between DOM windows, but with the same origin policy...
To get a tab's url, you may execute a content script on it. The content script can get the url using window.location.href
I'm in the process of making a Google Chrome extension, and encountered a problem.
I'm trying to upload and search through the DOM inside the popup.html.
Here is how I get the current tab (I found the script somewhere, credit doesn't belong to me):
chrome.windows.getCurrent(function(w) {
chrome.tabs.getSelected(w.id,function (response){
)};
My problem is this: I need to traverse through the DOM of the response. When trying to do so manually, I couldn't, as the response variable was now undefined for some reason, so using the Console isn't an option.
When trying to alert the response in the html file, it came as a object. Then, I tried to navigate through the response as if it has been the 'document' object, but no luck either.
Any help will be appreciated greatly.
You can get the selected tab for your popup by passing null as the window id to getSelected. () In your popup you can listen for extension events and execute a script to push the content to your popup:
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.action == "content")
{
console.log('content is ' + request.content.length + ' bytes');
}
});
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.executeScript(tab.id, { file: 'scripts/SendContent.js' } );
});
And finally the content script... I have it as "scripts/SendContent.js" in my extension folder, but the script is simple enough you could execute it by putting the code in the code property instead of the name in the file property of the object you pass to executeScript:
console.log('SendContent.js');
chrome.extension.sendRequest( {
action: "content",
host: document.location.hostname,
content: document.body.innerHTML
}, function(response) { }
);
Result:
POPUP: content is 67533 bytes
If you're having trouble, use console.log() and right-click on your page or browser action to inspect it and read your messages on the console (or debug your script from there).
I believe popups are sandboxed the same way that background pages are, so you'll need to use a content script to access the page DOM.
You can inject a content script with chrome.tabs.executeScript, handle your DOM traversal in the content script, then pass back the information you need from the content script to the popup using the message passing API.
I can try to elaborate on this if you give more information about the problem you're trying to solve.