WebExtensions tabs.executeScript does not work with "moz-extension://" pages

RESOLVED WORKSFORME

Status

WebExtensions
Untriaged
RESOLVED WORKSFORME
2 years ago
a month ago

People

(Reporter: fdsc, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [investigate] triaged)

Attachments

(1 attachment)

2.24 KB, application/x-xpinstall
Details
(Reporter)

Description

2 years ago
User Agent: Mozilla/5.0 (Win32) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36 OPR/36.0.2130.32

Steps to reproduce:

browser.tabs.create
	(
		{
			'url': /*'https://ya.ru'*/chrome.extension.getURL("http.html") + '?' + tab.id
		},
		function(tabHttp)
		{
			HttpViewer.selectedTabs['' + tab.id].tabs.push(tabHttp.id);
console.error('!!');

			chrome.tabs.executeScript
			(
				tabHttp.id,
				{
					//file: 'http.js'
					code: 'console.error("------------------------------------------------");',
					matchAboutBlank: true,
					runAt: 'document_start'
				},
				function(r)
				{
					console.error('!!!!');
					console.error(r);
				}
			);
		}
	);


Actual results:

If url: 'https://ya.ru' I see in console
"------------------------------------------------"
If url: chrome.extension.getURL("http.html") + '?' + tab.id
I see in console
"Unchecked lastError value: Error: No matching window"
and not
"------------------------------------------------"


Expected results:

I want execute script with the html page of my extension
(Reporter)

Updated

2 years ago
Blocks: 1213483

Updated

2 years ago
No longer blocks: 1213483
Priority: -- → P3
Whiteboard: [investigate] triaged

Comment 1

2 years ago
In reply to fdsc from comment #0
> Expected results:
> 
> I want execute script with the html page of my extension

It looks like this doesn't work like described as expected in Comment 0 even on Chromium (
https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/9P4BrVj-ls0/Y7BBnkMYqdgJ)

I created a small addon and tested the issue directly and, as anticipated by the link above, doesn't work on Chrome as well as on Firefox, and on Chrome the following message is raised:

> Cannot access contents of url "chrome-extension://EXTENSIONID/page.html". Extension manifest must request permission to access this host.

Given that it is not supported on Chrome and that there are other ways to run code dinamically in the other webextension pages that could compose an addon (e.g. get the window object using getViews and using window.eval, or add a tag script, or even better by exchanging messages using the provided messaging APIs) which are less convoluted and easier to follow by the reviewer if needed, I'm going to close it as wontfix.

Feel free to re-open if you have a specific usage scenario that it would not be covered by any of the available alternatives.
Status: UNCONFIRMED → RESOLVED
Last Resolved: 2 years ago
Priority: P3 → --
Resolution: --- → WONTFIX

Comment 2

2 years ago
You can't do this in Chrome either. Chrome complains 

«Permission 'chrome-extension://kekfohogmkpehdgchmplfcfakddjdnlb/http.html' is unknown or URL pattern is malformed.»

when the extension is installed [1], then 

«Cannot access contents of url "chrome-extension://kekfohogmkpehdgchmplfcfakddjdnlb/http.html". Extension manifest must request permission to access this host.»

when `chrome.tabs.executeScript` is called. Apparently "chrome-extension" was once an acceptable scheme but is now excluded [2].

[1] https://developer.chrome.com/extensions/match_patterns
[2] http://stackoverflow.com/questions/19042857/can-you-access-chrome-pages-from-an-extension#answer-19046408
(Reporter)

Comment 3

2 years ago
> even better by exchanging messages using the provided messaging APIs

I'm trying to implement in tab of my add-on the content script for exchange messages with it. How to do it other ways, not specified in the help.
Flags: needinfo?(lgreco)
(Reporter)

Comment 4

2 years ago
And. 
There's no message about lack of privileges. If we compare with chrome

"Unchecked lastError value: Error: No matching window"
in FireFox
and
"Extension manifest must request permission to access this host"
Status: RESOLVED → UNCONFIRMED
Resolution: WONTFIX → ---
(Reporter)

Updated

2 years ago
Blocks: 1213483

Comment 5

2 years ago
(In reply to fdsc from comment #3)
> > even better by exchanging messages using the provided messaging APIs
> 
> I'm trying to implement in tab of my add-on the content script for exchange
> messages with it. How to do it other ways, not specified in the help.

Here is a small example of messaging between an extension page opened in a tab and the background page:

- https://github.com/rpl/webextensions-examples/tree/example/tab2bg-messaging/tab2bg-messaging
Flags: needinfo?(lgreco)

Comment 6

2 years ago
(In reply to fdsc from comment #4)
> And. 
> There's no message about lack of privileges. If we compare with chrome
> 
> "Unchecked lastError value: Error: No matching window"
> in FireFox
> and
> "Extension manifest must request permission to access this host"

Yeah, both the error messages are not very helpful, even if in different ways.

I agree that a better error message it could be much much more helpful, but it is a different issue from what it is currently described by the summary and the description of this issue.

e.g. the new issue that we are now describing is about the error message, and it is not restricted to tabs.executeScript (because the same error message is generated from other tabs API when interacting with tabs which do not contains regular web pages).

Comment 7

2 years ago
The issues described above, in Comment 0 (related to the tabs.executeScript behavior) and Comment 4 (related to the not helpful error messages), do not seem to be related or blockers for "Bug 1213483 - Complete the implementation of chrome.webRequest".

could you explain in which way this issue is a blocker for Bug 1213483?
No longer blocks: 1213483
Flags: needinfo?(fdsc)
(Reporter)

Comment 8

2 years ago
> could you explain in which way this issue is a blocker for Bug 1213483?

Sorry. I apparently overworked and confused defects.



For this defect I will reply later.
Flags: needinfo?(fdsc)

Comment 9

2 years ago
(In reply to fdsc from comment #8)
> > could you explain in which way this issue is a blocker for Bug 1213483?
> 
> Sorry. I apparently overworked and confused defects.

No problem, I wanted to be sure that I wasn't missing anything and the block could be cleared.

Thanks for the confirmation.
(Reporter)

Comment 10

2 years ago
> Here is a small example of messaging between an extension page opened in a tab and the background page

I use chrome.tabs.executeScript in order to then send the script message to the background script.

In your example it is have not, but if I do it seems that nothing happens. That is, this method is also not working.

http.html
<html>
<head>
<meta http-equiv=Content-Type content="text/html;charset=windows-1251" />
</head>
<body id=body>
<script src="http.js"></script>
</body>
</html>

http.js
// chrome.runtime.sendMessage({'all': 'all'});
console.error('AAAAAAAAAAAAAAAAAAAAAAAA'); // TODO

var httpViewerCnt = {};

httpViewerCnt.update = function(message)
{
console.error('httpViewerCnt.update');
console.error(message);
console.error(httpViewerCnt.tabId);
};

chrome.runtime.onMessage.addListener(httpViewerCnt.update);


In background.js
...
console.error('to ' + tabIdE);
console.error('object ' + tabId);
browser.tabs.sendMessage(tabIdE, {tabId: tabId, tabIdE: tabIdE, tab: HttpViewer.selectedTabs['' + tabId]});

...
browser.tabs.create
(
	{
		'url': chrome.extension.getURL("http.html") + '?' + tab.id
	},
	function(tabHttp)
	{
		HttpViewer.selectedTabs['' + tab.id].tabs.push(tabHttp.id);
console.error('created ' + tabHttp.id + ' for ' + tab.id);
	}


I see the following in console

When I create a tab
created 3 for 2
AAAAAAAAAAAAAAAAAAAAAAAA


When triggered the code for send the message to content script
to 3
object 2


And then, after several seconds
Error: Could not establish connection. Receiving end does not exist.



So I decided that executeScript more the right decision. But it is also not working.
What method then should work? Or I doing something wrong?

P.S. And, in addition, it remains the unclear error messages.
Flags: needinfo?(lgreco)
(Reporter)

Comment 11

2 years ago
Sorry, not right
> I use chrome.tabs.executeScript in order to then send the script message to the background script.
right

> I use chrome.tabs.executeScript in order to then send the message from the background script to content script.
(Reporter)

Comment 12

2 years ago
Created attachment 8766959 [details]
Sent message does not reach

Updated

2 years ago
Status: UNCONFIRMED → NEW
Ever confirmed: true

Comment 13

2 years ago
There are two, maybe three problems with the attached extension. First, you're sending messages to tabs which have no content script. In an extension page you include script with a `<script>` tag as you did in `http.html`, but in other pages you need either a "content_scripts" property in `manifest.json`
  "content_scripts":  [{
    "matches": ["<all_urls>"],
    "js": ["http.js"]
  }]
Or, you can add the script with `chrome.tabs.executeScript` as you originally tried to do (but only for pages you could match with "content_scripts" - basically `executeScript()` == "content_scripts").

Second, you are sending messages in the `webRequest.onBeforeRequest` listener, before extension script is running in the tab. You can't send messages to a content script before `webNavigation.onCommitted` (or maybe `webRequest.onResponseStarted` or `webRequest.onCompleted`, but see [1]).

Third (maybe), you are trying to send messages to the tab that was active when you clicked the toolbar button, not to the extension tab that opens after the button is clicked. Is that what you want?

Also, your extension pages (including the background page) all run in the same process and can "see" one another via `chrome.extension.getViews` and `chrome.extension.getBackgroundPage`. If it's convenient, one extension page can directly use another extension page's globals, without passing messages between views. (Again, only between extension pages, not between an extension page and a content script.)

(NB: I replaced `browser.tabs.*` with `chrome.tabs.*` in your extension and tested in Chrome. Develop in Chrome, port to Firefox - you'll be happier.)

[1] https://developer.chrome.com/extensions/webNavigation#relation_to_webRequest

Comment 14

2 years ago
(In reply to Luca Greco [:rpl] from comment #1)
> Given that it is not supported on Chrome and that there are other ways to
> run code dinamically in the other webextension pages that could compose an
> addon ... I'm going to close it as wontfix.

Off-topic, but I do want to add that permitting `executeScript` with `moz-extension:` pages would allow one extension to add features to some other extension (bug 1223642 e.g.) without relying on the second, target extension implementing and publishing an API. Today it can be done with XUL overlays, but tomorrow...
(Reporter)

Comment 15

2 years ago
> In an extension page you include script with a `<script>` tag as you did in `http.html`, but in other pages you need either a "content_scripts" property in 

It is impossible to do. I just asked how insert content script. But in manifest it will not work. After all, this is the kind of page.

1. <script> in html - impossible
2. ExecuteScript - impossible
3. Manifest - impossible


> Or, you can add the script with `chrome.tabs.executeScript` as you originally tried to do (but only for pages you could match with "content_scripts" - basically `executeScript()` == "content_scripts")

This is not a solution too.


> you are sending messages in the `webRequest.onBeforeRequest` listener, before extension script is running in the tab

This is not so.
BeforeRequest triggered to load another page. It's not BeforeRequest to the page that loaded the script.

> not to the extension tab ... Is that what you want?
I want to send a request to the extensions tab.

> Also, your extension pages (including the background page) all run in the same process and can "see" one another via `chrome.extension.getViews` and `chrome.extension.getBackgroundPage`

I'm afraid that's also not what I need.
Could you give a link where it tells you what is running in the same process?


I thought that background should work in a single process. Page in other processes. At that, content-script runs in other processes.
Maybe I don't understand something.

However, I need the content-script. As I understand it, only he can modify the DOM in page.

The my task is very simple. I need to display information to the user in the extensions page.

> pages would allow one extension to add features to some other extension

The most secure computer is a turned off computer.
But yet, I prefer to use enabled computers.



I need the way so I can display information on the extensions tab.
Flags: needinfo?(lgreco)

Comment 16

2 years ago
OK, in Firefox 47 `chrome.tabs.sendMessage` fails when the tab contains an extension page. The method returns a `Promise` that never resolves, and the `onMessage` listener is never called. That's a bug.

You can use `chrome.runtime.sendMessage` instead to broadcast each message to all of your extension pages. Include the extension page's tab ID in each message, and let each page identify its own messages. The tab ID is already in your messages (`tabIdE`), so you just need to pass the page its own tabId when you create it, in the URL query string or something.

(In reply to fdsc from comment #15)
> It is impossible to do. ...
> This is not a solution too. ...
> This is not so. ...

Apologies; you're right of course. My eyes saw "HttpViewer.sendMessage" but my brain read "chrome.tabs.sendMessage", so I completely misunderstood what you were doing with the tabs.

> Could you give a link where it tells you what is running in the same process?

I don't have a link for you, but I do know that `chrome.extension.getViews` returns an array of `Window` objects, that the `window`s of all `chrome-extension://` pages (including the background page) are in the array, and that any of them can use the `window` object properties of the others directly, without messaging or callbacks or any other scheme to coordinate access. 

I assumed they were all in one process because one extension page can use functions that block from the `window` object of another extension page. I shouldn't have said "same process"; I don't really know. 

> I thought that background should work in a single process. Page in other
> processes. At that, content-script runs in other processes.

A content script is basically code with its own semi-privileged namespace ("default object"? "global object"? "window object"? - sorry, I don't know the right word) that's added to a low-privilege page, and which has access to the same DOM. Content script and page script run in the same process (I think) so that they can't both try to change the DOM at the same time. One DOM, two code compartments, one privileged and one not, both in the same process.

An extension page (`moz-extension://`) is basically code with a privileged namespace and a DOM. You can imagine adding a content script to it, a second code compartment with its own less-privileged namespace, but Chrome has never done that - why add your own semi-privileged content script to your privileged extension page (which is what you tried to do) when you can just include it as privileged code?

An extension page in a tab is not a content page. Maybe that's what's confusing. (I find it confusing.)

Each extension page has its own (privileged) namespace, but also has access to those of your other extension pages (including the background page) via `chrome.extension.getViews`. N DOMs (one per extension page), N code compartments, all privileged, all in the same process (I think, since they can use each other's variables without colliding).

So, you could do something like this in your `tabs.create` callback:

  var ww = chrome.extension.getViews(); // all chrome-extension:// windows
  var w = ww[ww.length - 1]; // the chrome-extension:// window just created
  w.tabId = tabHttp.id; // a global variable window.tabId in that window

instead of passing the tab ID in the URL query string or in a message.

> However, I need the content-script. As I understand it, only he can modify the DOM in page.

Not exactly. `http.html` is an extension page, so any extension page can modify its DOM. Open a `http.html` page in your attached extension, then enter this in the background page's console:

  var ww = chrome.extension.getViews();
  var w = ww[ww.length - 1];
  var d = w.document;
  var e = d.createElement('h1');
  e.textContent = "wocka wocka!";
  d.body.appendChild(e);

Or, open two `http.html` pages, open Console for the first page, copy+paste the code, and see the DOM changes in the second page.

So, until the messaging bug is fixed, you can either use `chrome.runtime.sendMessage` with a tab ID in the message, or you can modify the various `http.html` DOMs from the background script.
(Reporter)

Comment 17

2 years ago
> OK, in Firefox 47 `chrome.tabs.sendMessage` fails when the tab contains an extension page. The method returns a `Promise` that never resolves, and the `onMessage` listener is never called. That's a bug.

I couldn't find where this bug?
And, I have it on FireFox DE (49)
If you do not mind, could you specify its number?

Comment 18

2 years ago
Bug 1209869, though it may or may not be a bug (bug 1209869#c3). In Chrome it works, in Firefox it fails, and in both the documentation says "Sends a single message to the content script(s) in the specified tab" [1] [2].

[1] https://developer.chrome.com/extensions/tabs#method-sendMessage
[2] https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/sendMessage
(Reporter)

Comment 19

2 years ago
> So, until the messaging bug is fixed, you can either use `chrome.runtime.sendMessage` with a tab ID

Also not working


I think executeScript still have to work for tabs of the same extension. Do not see for this obstacle.
But, in principle, we can assume that it was by  design. It is only necessary to describe the relevant limitations in the documentation. So this is a bug in the documentation.
(Reporter)

Comment 20

2 years ago
> Also not working

No, it is wrong. I see that it worked. Thanks.

Comment 21

2 years ago
Could someone in this bug update it with what needs to be done please, there's been quite a discussion in the comments. Is duping to bug 1209869 appropriate?

Comment 22

2 years ago
Close it? This was a misunderstanding. fdsc created a tab with a UI page (extension process) and tried to run code in it with `tabs.executeScript` (content processes). Very reasonable, but wrong in both Chrome and Firefox. Most of the palaver was persuading fdsc that a UI page in a tab is background and not content. 

There _is_ utility in injecting code with a content script context into another extensions' UI page. An add-on like Stylish Custom [1], which adds features to the Stylish editor with an XUL overlay, could be developed as a WebExtension extending a WebExtension Stylish without the Stylish developer explicitly exposing a messaging interface to allow that. However, I don't know if you can nest contexts that way, and that's not why fdsc filed this bug.

Bug 1209869 is relevant to fdsc's problem but not to this bug. In Chrome, `tabs.sendMessage` will reach any page in a tab. In Firefox, it reaches content scripts but not UI pages. fdsc used `tabs.sendMessage` to signal his UI page, reasonable, but it failed.

[1] https://addons.mozilla.org/en-US/firefox/addon/stylish-custom/

Comment 23

2 years ago
Thanks for the summary, Nancy, closing.
Status: NEW → RESOLVED
Last Resolved: 2 years ago2 years ago
Resolution: --- → WORKSFORME

Updated

a month ago
Product: Toolkit → WebExtensions
You need to log in before you can comment on or make changes to this bug.