chrome.downloads API: How to know which tab the user downloaded a file form:

82 views
Skip to first unread message

Moe Bazzi

unread,
Sep 30, 2022, 12:49:14 PM9/30/22
to Chromium Extensions
Hello everyone,

Using the chrome.downloads API, when a user initiates a download, (in either the onCreated or onDeterminingFileName event listeners), how can I know from which tab the user downloaded the file from? 

My best method currently is to get the current active tab, but this isnt always correct as the user can click a button to initiate a download, then switch their tab before the download actually starts in the browser. 

Also, what is the DownloadItem.referrer attribute exactly? Maybe this could help.

Thanks!

wOxxOm

unread,
Oct 1, 2022, 10:31:22 AM10/1/22
to Chromium Extensions, bazz...@gmail.com
AFAIK chrome.webRequest.onBeforeRequest is typically used for this. It still works in MV3 because this task doesn't need "blocking" in the third parameter of addListener. If it won't show anything, check the other fields in DownloadItem like byExtensionId.

The referrer contains the URL of the page/frame that originated the download. I don't know though if the downloads API will still report it if referrer-policy header of the request wants to hide it. The webRequest API should still see it anyway.

Moe Bazzi

unread,
Oct 1, 2022, 12:37:06 PM10/1/22
to wOxxOm, Chromium Extensions
Thanks! But when I intercept a request with chrome.webRequest.onBeforeRequest, how can I know that this is a request to download a file? 

wOxxOm

unread,
Oct 1, 2022, 1:11:46 PM10/1/22
to Chromium Extensions, bazz...@gmail.com, Chromium Extensions, wOxxOm
You'll have to infer it somehow.

  • I see the download requests weirdly have type: "main_frame" which is meant only for navigations that are displayed as a page, not downloaded, so when you see it for a URL that has a common file extension you can suspect it's a download. 
  • onHeadersReceived listener (added with "responseHeaders" mode) in details.responseHeaders shows that many (most?) downloads have "Content-Disposition" header with "attachment" inside.
  • Check "Content-Type" header in  onHeadersReceived.
When all the signs are present I'd say it's a reliable indication, but I didn't test it myself, so you can experiment yourself or inspect some other extensions. Note that a previously installed extension can use declarativeNetRequest (or a blocking webRequest if it's a policy-enforced extension) to modify the received headers so your extension will see the result not the original.

Moe Bazzi

unread,
Oct 1, 2022, 4:19:12 PM10/1/22
to wOxxOm, Chromium Extensions
Awesome, thank you so much!

Moe Bazzi

unread,
Oct 1, 2022, 9:48:59 PM10/1/22
to wOxxOm, Chromium Extensions
Since my extension also has content scripts injected into all tabs and frames, another method I can use it to listen for click events on anchor elements that have a 'download' attribute set on them. This will let me know where the user is initiating a download from. Would you advise against this method or see any downfalls to it? 

wOxxOm

unread,
Oct 2, 2022, 2:47:30 AM10/2/22
to Chromium Extensions, bazz...@gmail.com, Chromium Extensions, wOxxOm
It won't catch all downloads e.g. those initiated via window.open('https://foo.bar/blabla') or an <a> link with a similar URL that doesn't contain a file extension. Submitting a <form> can also result in a download.

Moe Bazzi

unread,
Oct 2, 2022, 10:12:57 AM10/2/22
to wOxxOm, Chromium Extensions
Right.

Lets say I wanted to also intercept the actual contents of the downloads and stop the browser from downloading the file to the users computer. You can stop downloads with the chrome.downloads API but you cant get the actual contents of the download from the API. My current method is to stop the download, and then refetch the DownloadItem.url or DownloadItem.finalUrl, but this sometimes responds with wrong data or a 403.


> those initiated via window.open('https://foo.bar/blabla') or an <a> link with a similar URL that doesn't contain a file extension. Submitting a <form> can also result in a download.
Do you think it would it be possible and safe to monkey patch these methods (and the fetch and XMLHttpRequest.send methods to check for a content-disposition header) in order to be able to intercept the response body of the download?




wOxxOm

unread,
Oct 2, 2022, 10:39:32 AM10/2/22
to Chromium Extensions, bazz...@gmail.com, Chromium Extensions, wOxxOm
Patching XHR/fetch would work but they can't generate a browser download directly (you need to create an <a> element with "download" attribute for that). Patching the other methods won't help because it's a new main_frame (or possibly sub_frame) navigation i.e. a new page context which doesn't include the currently running code. BTW it explains why downloads have a main_frame type: it's an intercepted navigation.
Reply all
Reply to author
Forward
0 new messages