Skip to content

Support web downloads in browser adapter#2534

Open
a1573595 wants to merge 4 commits into
cfug:mainfrom
a1573595:cw/2408
Open

Support web downloads in browser adapter#2534
a1573595 wants to merge 4 commits into
cfug:mainfrom
a1573595:cw/2408

Conversation

@a1573595
Copy link
Copy Markdown
Contributor

@a1573595 a1573595 commented Jun 1, 2026

Fixes #2408

This PR adds Web support for Dio.download in dio_web_adapter.

Previously, DioForBrowser.download always threw UnsupportedError, so browser users could not call Dio.download at all. This change keeps the existing public API and implements browser downloads by fetching the response bytes through Dio, creating a Blob object URL, and triggering a hidden anchor click.

On Web, savePath is interpreted as the browser suggested filename, not as a filesystem path.

New Pull Request Checklist

  • I have read the Documentation
  • I have searched for a similar pull request in the project and found none
  • I have updated this branch with the latest main branch to avoid conflicts (via merge from master or rebase)
  • I have added the required tests to prove the fix/feature I'm adding
  • I have updated the documentation (if necessary)
  • I have run the tests without failures
  • I have updated the CHANGELOG.md in the corresponding package

Additional context and info (if any)

Implementation details:

  • DioForBrowser.download now supports browser downloads through Blob + object URL + hidden anchor click.
  • The regular Dio request path is preserved, including interceptors, headers, status validation, cancel token, timeout, and progress callbacks.
  • String savePath is treated as the suggested filename on Web.
  • FutureOr<String> Function(Headers) save path callbacks are supported after response headers are available.
  • FileAccessMode.append throws UnsupportedError on Web.
  • Bad responses and cancellations do not trigger a browser download.
  • Object URLs are revoked on success and failure paths.

Web limitations are documented:

  • browser decides the actual saved location
  • the whole response is loaded into memory before triggering the download
  • CORS still applies
  • FileAccessMode.append is unsupported
  • deleteOnError is a no-op on Web
  • custom lengthHeader values are not used for Web progress totals

Test result

Chrome:

dio-web-download-chrome-incognito.mp4

Safair:

dio-web-download-safari.mp4

Firefox:

dio-web-download-firefox-private.mp4

@a1573595 a1573595 requested a review from a team as a code owner June 1, 2026 01:32
Comment thread plugins/web_adapter/lib/src/dio_impl.dart
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks like the file needs more code comments.

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.

Updated.

  • Added comments around the Blob/object URL/anchor click implementation.
  • Expanded dio_web_adapter README to clarify that the browser schedules a download from a blob: URL, and that the returned Response only means Dio fetched the bytes and dispatched the download click.
  • Documented browser-controlled limitations: actual file write, filename handling, user prompts, page security policy, CORS, HTTP protocol handling through XHR, and required browser APIs.

@AlexV525
Copy link
Copy Markdown
Member

AlexV525 commented Jun 1, 2026

How will the browser react when triggered? Will a download task be scheduled by a blob request? I can only see the status update on the webpage itself, as the demonstration video doesn't reflect the browser's behavior. Also, I'd like to know if this has any limitations across Web protocol versions and different browsers.

@a1573595
Copy link
Copy Markdown
Contributor Author

a1573595 commented Jun 2, 2026

video doesn't reflect the browser's behavior. Also, I'd like to know if this has any

When triggered, Dio first finishes the XHR request as bytes, then creates a Blob, an object URL, and clicks a hidden <a download> element. That schedules a normal browser download task for the generated blob: URL.

I validated this behavior with Chrome, Firefox, and Safari demos. The UI differs per browser: Chrome/Firefox show a clearer download entry/panel, while Safari may only show a subtle toolbar/download indicator, but the file is still saved.

Limitations:

  • The original request is still XHR, so CORS applies.
  • The full response is held in memory before the Blob download starts.
  • Dio can suggest the filename, but the browser decides the final save location/name.
  • There is no append/delete-on-error filesystem behavior on Web.
  • HTTP/1.1, HTTP/2, or HTTP/3 should not change this behavior; transport is handled by the browser before the Blob URL download is scheduled.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Code Coverage Report: Only Changed Files listed

Package Base Coverage New Coverage Difference
Overall Coverage 🟢 89.18% 🟢 89.18% ⚪ 0%

Minimum allowed coverage is 0%, this run produced 89.18%

@AlexV525
Copy link
Copy Markdown
Member

AlexV525 commented Jun 6, 2026

Coverage info doesn't seem to be valid somehow. Paths are missing from it. cc @kuhnroyal

Copy link
Copy Markdown
Contributor

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 adds Web support for Dio.download when using dio_web_adapter, enabling browser downloads by fetching response bytes through Dio and triggering a Blob-backed download via a temporary anchor click. It also updates documentation and adds browser-only tests to validate the new behavior and edge cases.

Changes:

  • Implement DioForBrowser.download by requesting ResponseType.bytes, resolving the suggested filename, and triggering a browser download via a Blob URL.
  • Introduce a dedicated download_trigger utility with test hooks and add comprehensive browser tests for download behavior, cancellation, and error paths.
  • Document Web-specific limitations/semantics and update changelogs and README docs accordingly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
plugins/web_adapter/lib/src/dio_impl.dart Implements DioForBrowser.download to fetch bytes and trigger a browser download.
plugins/web_adapter/lib/src/download_trigger.dart Adds Blob/object-URL + anchor-click download trigger with test hooks.
plugins/web_adapter/test/download_test.dart Adds browser-only tests covering download success, naming, cancellation, and trigger failures.
plugins/web_adapter/README.md Documents how Web downloads work and their limitations.
plugins/web_adapter/CHANGELOG.md Notes new Web Dio.download support.
dio/README.md Documents Web-specific download semantics/limitations in main README.
dio/README-ZH.md Adds Chinese documentation for Web download semantics/limitations.
dio/lib/src/dio.dart Updates API docs for download to describe Web behavior and constraints.

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

Comment on lines +94 to +96
response.headers
..set('redirects', response.redirects.length.toString())
..set('uri', response.realUri.toString());
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.

Cannot download the file in the browser

3 participants