Skip to content

Let browser handle downloads directly and support multi-file download#294

Open
ZNikke wants to merge 6 commits intodCache:masterfrom
ZNikke:let-browser-download
Open

Let browser handle downloads directly and support multi-file download#294
ZNikke wants to merge 6 commits intodCache:masterfrom
ZNikke:let-browser-download

Conversation

@ZNikke
Copy link
Copy Markdown
Contributor

@ZNikke ZNikke commented May 12, 2023

Currently dCacheView handles downloads by first doing the download and only when the download has completed it passes the object along for the browser to handle. The result is no feedback at all for users when initiating download of large files since the save dialog is shown on completion, and huge files might not download at all if the temporary browser download location runs out of space. Further frustrating users, you can select multiple files but is not allowed to select download.

Work around this by letting the browser handle the download instead, the method chosen is to create a temporary Anchor element to drive the download action as it has an explicit download attribute and avoids issues with modern browser pop-up blockers. Since username/password (Basic) auth can't be reliably passed along a short-lived Macaroon is created to handle the download. Existing Macaroons are used as-is to handle download in the shared-files view. Sessions with certificate authentication are assumed to work as-is, bypassing the Macaroon generation stage. The same basic mechanism is used to allow download of multiple files, this is also found to be easier to use on tablets/smartphones compared to the common .zip archive solution.

The result is a decent end user experience when downloading files, including multiple huge files that are common in a scientific data store.

Credits go to various threads on https://stackoverflow.com/ for explaining numerous corner cases and nuances in this area.

Fixes: #269
Fixes: #268

@ZNikke
Copy link
Copy Markdown
Contributor Author

ZNikke commented May 15, 2023

Ugh, discovered that I confused myself when testing to think that it worked in the shared-files view. It doesn't, in the sense that the shared-files view uses another code path with similar functionality as the main one and thus still has the old behavior.

I'll look into making this code be used there as well, to match the pull request description.

@ZNikke ZNikke force-pushed the let-browser-download branch from 757a1fb to bb332f3 Compare May 16, 2023 11:55
@ZNikke ZNikke changed the title Let browser handle downloads directly Let browser handle downloads directly and support multi-file download May 16, 2023
@ZNikke
Copy link
Copy Markdown
Contributor Author

ZNikke commented May 16, 2023

There, I think this works as intended now.

Currently dCacheView handles downloads by first doing the download and
only when the download has completed it passes the object along for the
browser to handle. The result is no feedback at all for users when
initiating download of large files since the save dialog is shown on
completion, and huge files might not download at all if the temporary
browser download location runs out of space.

Work around this by letting the browser handle the download instead, the
method chosen is to create a temporary Anchor element to drive the
download action as it has an explicit download attribute and avoids
issues with modern browser pop-up blockers. Since username/password
(Basic) auth can't be reliably passed along a short-lived Macaroon is
created to handle the download. Existing Macaroons are used as-is to
handle download in the shared-files top-level view. Sessions with
certificate authentication are assumed to work as-is, bypassing the
Macaroon generation stage.

The result is a decent end user experience when downloading files,
including huge files that are common in a scientific data store. Missing
in this patch is handling of subdirectories in the shared-files view.

Credits go to various threads on https://stackoverflow.com/ for
explaining numerous corner cases and nuances in this area.

Fixes: dCache#269

Signed-off-by: Niklas Edmundsson <nikke@hpc2n.umu.se>
dCacheView is limited to file-by-file downloads, which is frustrating
users since there is support for multi-file selection.

This patch builds on the previous one to enable downloads for multi-file
selections. The simplest solution is implemented that triggers multiple
file downloads in the browser, this is also found to work best with
tablets and smartphones, where the traditional method by handling
multi-file download by providing a .zip archive of the files is really
cumbersome to handle.

There is also a completion of the implementation to handle
sub-directories in the shared-files view.

The end result is that it is now possible to select multiple files in a
directory and then download them in a smooth manner.

Fixes: dCache#268

Signed-off-by: Niklas Edmundsson <nikke@hpc2n.umu.se>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes dCacheView’s download flow to rely on the browser’s native download handling (instead of downloading into a Blob first), and adds support for downloading multiple selected files by initiating multiple direct downloads. It introduces short-lived macaroons for authenticated downloads where the browser cannot reliably replay the current auth.

Changes:

  • Add a new download initiation path (app._initiateDownload) that triggers a native browser download via a temporary <a download> link, optionally appending/obtaining a macaroon.
  • Enable “Download” in the multi-selection context menu and initiate multi-file downloads.
  • Reuse the same download initiation logic for the shared-files page.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 6 comments.

File Description
src/scripts/dv.js Adds native-download helpers, macaroon-based download initiation, and multi-file download triggering.
src/elements/dv-elements/contextual-content/namespace-contextual-content.html Enables download action for multi-selection in the context menu.
src/elements/dv-elements/file-sharing/shared-files-page/shared-files-page.js Switches shared-file downloads to use the new central download initiation logic.
src/elements/dv-elements/files-viewer/files-viewer.html Minor formatting change (closing tag alignment).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 246 to 253
} else if (this.multipleSelection) {
this.$.delete.addEventListener('tap', this._delete.bind(this));
this.$.move.addEventListener('tap', this._move.bind(this));
// FIXME: Is this the place to figure out if any
// directories are selected and disable download if
// that's the case?
this.$.download.addEventListener('tap', this._openOrDownload.bind(this));
} else if (this.currentDir) {
Comment thread src/scripts/dv.js Outdated
Comment thread src/scripts/dv.js
Comment on lines +515 to +540
const fileURL = getFileWebDavUrl(file.filePath, "read")[0];
let authval = app.getAuthValue();

// Unconditionally use existing macaroon if available
let macaroon = undefined;
if (file.macaroon) {
macaroon = file.macaroon;
}
else if(file.authenticationParameters !== undefined && file.authenticationParameters.scheme === "Bearer") {
macaroon = file.authenticationParameters.value;
}

if(macaroon !== undefined) {
let u = new URL(fileURL);
u.searchParams.append('authz', macaroon);
_downloadFile(u);
}
else if(!authval) {
/*
* No explicit auth, so using cert auth, which means we can
* just access the file directly without having the user
* re-login.
*/
_downloadFile(fileURL);
}
else {
Comment thread src/scripts/dv.js Outdated
Comment on lines +592 to +595
/* Need to stagger starts to allow browser to start
* this download before initiating the next one.
*/
setTimeout(app._initiateDownload, i*1000, toDL[i]);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial reason for the delay was browsers simply refusing to trigger multiple downloads otherwise. This might well have changed, but this needs to be carefully tested using multiple browsers/OS:es. Testing the lower hanging fruits first.

Comment thread src/scripts/dv.js Outdated
}, false);
macaroonWorker.addEventListener('error', (e) => {
macaroonWorker.terminate();
// FIXME: Display an error dialog somehow
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error dialog is better than a FIXME, hard to test so hope it works...

'upauth' : this.getAuthValue(),
'return': 'blob'
});
app._initiateDownload(e.detail.file);
@ZNikke
Copy link
Copy Markdown
Contributor Author

ZNikke commented May 6, 2026

I'll work through the suggested changes, most of it seems to make sense at a glance.

ZNikke and others added 4 commits May 6, 2026 15:58
…ones

Copilot review suggested change.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot review suggested change.
Copilot review suggested change.
Delaying download activation loses the user-activation gesture,
this can trigger browser to block actions as non-user initiated
unwanted actions.

Copilot review suggested change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feedback to user on download Feature Request: Allow multiple files download

2 participants