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

  1. Starts in nsURILoader.cpp, nsDocumentOpenInfo::OnStartRequest : here

  2. Through : this function call to nsDocumentOpenInfo::DispatchContent

  3. Checking if Content-Disposiotion is set to attachment : 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.

  4. Through : this function call to nsExternalHelperAppService::DoContent

  5. Through : this statement to nsExternalHelperAppService::DoContentContentProcessHelper

  6. Through : this call to ExternalHelperAppChild::SetHandler

  7. And then ExternalHelperAppChild::OnStartRequest

  8. Through : this call to nsExternalAppHandler::OnStartRequest

  9. And then nsExternalHelperAppService::DoContent() and then back to nsExternalHelperAppService::OnStartRequest()

  10. 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

  11. Dialog invoked here

  12. 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

  13. Through : this, a timer is started

  14. notify function here

  15. Through : this call to reallyShow() function

  16. After dialog, SaveToDisk function is invoked (Temp file to target file)

  17. SaveToDisk function

  18. Through : this call to nsExternalAppHandler::ContinueSave

  19. CreateTransfer invoked (where actual transfer starts) : here

  20. 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.