Closed Bug 1343940 Opened 7 years ago Closed 7 years ago

Need to know when webRequest.*.addListener event registration completes

Categories

(WebExtensions :: Untriaged, defect)

54 Branch
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED DUPLICATE of bug 1300234

People

(Reporter: imprec, Unassigned)

References

Details

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:54.0) Gecko/20100101 Firefox/54.0
Build ID: 20170302030206

Steps to reproduce:

Both WebRequest.onBeforeSendHeaders and WebRequest.onSendHeaders are async whereas the other events registration are synchronous.

Here's what I do :

```
chrome.webRequest.onBeforeSendHeaders.addListener((details) => console.log('onBeforeSendHeaders', details.url), { urls: ['<all_urls>'] });
chrome.webRequest.onCompleted.addListener((details) => console.log('onCompleted', details.url), { urls: ['<all_urls>'] });
chrome.webRequest.onErrorOccurred.addListener((details) => console.log('onErrorOccurred', details.url), { urls: ['<all_urls>'] });
chrome.webRequest.onHeadersReceived.addListener((details) => console.log('onHeadersReceived', details.url), { urls: ['<all_urls>'] })
chrome.webRequest.onResponseStarted.addListener((details) => console.log('onResponseStarted', details.url), { urls: ['<all_urls>'] })
chrome.webRequest.onSendHeaders.addListener((details) => console.log('onSendHeaders', details.url), { urls: ['<all_urls>'] })

fetch('https://blackfire.io');
```

And I got this in the console:
```
onHeadersReceived "https://blackfire.io/"  
onResponseStarted "https://blackfire.io/"  
onCompleted "https://blackfire.io/"  
```


Note : When I do the fetch on next tick:
```
chrome.webRequest.onBeforeSendHeaders.addListener((details) => console.log('onBeforeSendHeaders', details.url), { urls: ['<all_urls>'] });
chrome.webRequest.onCompleted.addListener((details) => console.log('onCompleted', details.url), { urls: ['<all_urls>'] });
chrome.webRequest.onErrorOccurred.addListener((details) => console.log('onErrorOccurred', details.url), { urls: ['<all_urls>'] });
chrome.webRequest.onHeadersReceived.addListener((details) => console.log('onHeadersReceived', details.url), { urls: ['<all_urls>'] })
chrome.webRequest.onResponseStarted.addListener((details) => console.log('onResponseStarted', details.url), { urls: ['<all_urls>'] })
chrome.webRequest.onSendHeaders.addListener((details) => console.log('onSendHeaders', details.url), { urls: ['<all_urls>'] })

setTimeout(() => fetch('https://blackfire.io'));
```

I got the expected output in the console:

```
onBeforeSendHeaders "https://blackfire.io/" 
onSendHeaders "https://blackfire.io/" 
onHeadersReceived "https://blackfire.io/" 
onResponseStarted "https://blackfire.io/" 
onCompleted "https://blackfire.io/"  
```


Actual results:

See previous box


Expected results:

See previous box
All events are asynchronous. The other events just happen to be dispatched later.
Status: UNCONFIRMED → RESOLVED
Closed: 7 years ago
Resolution: --- → INVALID
Hello [:kmag] and thank you for taking time for this ticket.

I think we misunderstood, at least I did not express myself very well.
My ticket is not about event dispatching but event handlers registration.

Functions WebRequest.onBeforeSendHeaders.addListener and WebRequest.onSendHeaders.addListener are supposed to be synchronous, listener should be called once they have been called.

It appears this is true for all WebRequest.*.addListener functions except the both I mentioned.

Please have a look at the code I mentioned above. For the both function, listener are called on next tick.

Hope you'll better understand what I report.

Regards,
Status: RESOLVED → UNCONFIRMED
Resolution: INVALID → ---
Summary: WebRequest.onBeforeSendHeaders and WebRequest.onSendHeaders are async whereas all WebRequest.* events are sync → WebRequest.onBeforeSendHeaders.addListener and WebRequest.onSendHeaders.addListener are async whereas all WebRequest.*.addListener events are sync
Request event handler registration is always asynchronous. The reason that some events fire in your case and others don't is that some events happen later than others.
Status: UNCONFIRMED → RESOLVED
Closed: 7 years ago7 years ago
Resolution: --- → INVALID
Hello again,

Actually, if it's asynchronous, there's no way to know an event listener has been registered at the moment.
This is an issue for two reason:

 - the addListener function should return a promise, or a extra argument should be passed as a callback to know when the listener is registered
 - The Chrome implementation is synchronous

Regards,
(In reply to Romain Neutron from comment #4)
>  - The Chrome implementation is synchronous

The Chrome implementation isn't synchronous, it just has different timing characteristics, and the listener happens to be registered in the parent process before the initial stages of the fetch request are proxied to it.
At my code level, it appears synchronous.

Anyway, an asynchronous call should return a promise, a callback or anything that could determine when it's been done, otherwise how would you do?
(In reply to Romain Neutron from comment #6)
> Anyway, an asynchronous call should return a promise, a callback or anything
> that could determine when it's been done,

That would probably be a good idea, yes.

> otherwise how would you do?

That depends. What exactly are you trying to do?
(In reply to Kris Maglione [:kmag] from comment #7)
> (In reply to Romain Neutron from comment #6)
> > Anyway, an asynchronous call should return a promise, a callback or anything
> > that could determine when it's been done,
> 
> That would probably be a good idea, yes.
> 
> > otherwise how would you do?
> 
> That depends. What exactly are you trying to do?

Can't speak for Giorgio, but a very plausible use case that I have encountered multiple times is:

1. Register webRequest handler for a specific URL.
2. Trigger request to that URL
3. When the request finishes, remove the webRequest handler.

What I currently do is execute step 1,
call any async API (e.g. browser.runtime.getPlatformInfo),
and in its callback continue at step 2.
I know that it works in the current implementation, but there is no guarantee that it will work in the future.

Having addListener return a Promise would be good IMO.
It also allows add-on devs to handle errors in a more graceful way (this can be useful for feature detection when we extend the webRequest API filters/blocking responses in the future).
Status: RESOLVED → REOPENED
Ever confirmed: true
Resolution: INVALID → ---
Summary: WebRequest.onBeforeSendHeaders.addListener and WebRequest.onSendHeaders.addListener are async whereas all WebRequest.*.addListener events are sync → Need to know when webRequest.*.addListener event registration completes
(In reply to Rob Wu [:robwu] from comment #8)
> Can't speak for Giorgio, but a very plausible use case that I have

Sorry, I meant Romain (the reporter). I've read too much reports from Giorgio today ;)
See Also: → 1300234
Status: REOPENED → RESOLVED
Closed: 7 years ago7 years ago
Resolution: --- → DUPLICATE
Product: Toolkit → WebExtensions
You need to log in before you can comment on or make changes to this bug.