The long forgotten download flow
Ability to download is one of the most archaic features of any browser, intoduced during web’s infancy. Most of the download related core code lies untouched and rusty for a couple of decades. Yes, decades. This is surprising given how mercurial Firefox code base is :p
In order to proceed, I spent sufficient time reading through and documenting the download flow.
How?
Searchfox, the real MVP.
Searchfox is a source code indexing tool for Mozilla Firefox. It indexes C++, Rust, and JavaScript code.
It indexes idl, xul, xbl as well. It includes cross-referencing and path filtering features also.
Gone are the ctrl + shift + f
days; Yeah, that’s how I searched through the code base, back when I was dense and unaware of source code indexers. Thanks Nihanth :)
Searchfox is the best at what it does (imo). By the way, there are other places you can search through the Firefox code base like dxr and hg.mozilla.org. Searchfox however is recommended : Bill McCloskey’s compariosion Blog.
The flow
Here is the the download flow I discovered by digging through the ‘long forgotten’ code base. I started from uriloader/exthandler/nsExternalHelperAppService.cpp
and traced up and down the function call stack. Here’s what I found :
(It starts at nsIURILoaded.cpp
because I was convinced tracing back further is simply not necessary for the problem statement at hand)
I have given Searchfox permalinks to all the code points
-
Starts in
nsURILoader.cpp
,nsDocumentOpenInfo::OnStartRequest
: here -
Through : this function call to nsDocumentOpenInfo::DispatchContent
-
Checking if
Content-Disposiotion
is set toattachment
: here.
I think we should plug in our permissions checking code somewhere here. The temp file has not been created here and the download hasn’t started yet. So this means download spam does not hog user’s bandwidth. -
Through : this function call to nsExternalHelperAppService::DoContent
-
Through : this statement to nsExternalHelperAppService::DoContentContentProcessHelper
-
Through : this call to ExternalHelperAppChild::SetHandler
-
Through : this call to nsExternalAppHandler::OnStartRequest
-
And then
nsExternalHelperAppService::DoContent()
and then back tonsExternalHelperAppService::OnStartRequest()
-
Decision on whether or not to invoke the dialog starts here.
By now, the temp file has been set up and transfer has begun in the background. We can also put permissions checking code here and cancel the download based on results. This deletes the temp file and stops the transfer.
If dialog need not be invoked,SaveToDisk
is directly called : here -
Dialog invoked here
-
Dialog
show
function is here :nsUnknownContentTypeDialog.show()
We should put permissions checking code here if we should always respect user’s preferences for a particular mime type irrespective of how many downloads are triggered -
Through : this, a timer is started
-
notify
function here -
Through : this call to reallyShow() function
-
After dialog, SaveToDisk function is invoked (Temp file to target file)
-
Through : this call to nsExternalAppHandler::ContinueSave
-
CreateTransfer
invoked (where actual transfer starts) : here -
Create Transfer function Through : this statement, the flow finally enters the download module.
After this download.start() is eventually called.
My proposal suggested that I plug in permission checking code somewhere here. However, it appears I was so wrong and some major proposal refactoring is required.