Skip to content

Keep a capture's shared download client open until the capture ends - #232

Merged
SunkenInTime merged 1 commit into
icarus-cloudfrom
capture-shared-client-fix
Sep 29, 2026
Merged

SunkenInTime merged 1 commit into
icarus-cloudfrom
capture-shared-client-fix

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Hotfix for #229, which is live on the beta. Greptile caught it while reviewing #230.

Bug: a web screenshot of a page with two or more cloud images, or with one whose signed URL has expired, fails with "Couldn't load the images on this page."

Cause: my last change to #229 aborts a failed capture's other downloads. To do that, it gave the capture's downloads one shared client through http.runWithClient. But package:http's top-level http.get closes whatever client it picks up once its request finishes (_withClient → client.close()). So the first download to finish closes the shared client:

  • In the browser, BrowserClient.close() aborts the other downloads in flight.
  • A refresh after an expired URL is refused by the closed client.

Nothing is saved wrong, but screenshots of those pages don't work. Desktop is mostly unaffected, since cloud images there usually come from cached files.

Fix: the capture passes its client to the fetcher explicitly, and downloadCloudImageBytes takes an optional client and calls client.get. Now only the capture closes the client, when it's done, which still aborts leftover downloads after a failure. The fetcher type's doc says to use client.get, never the top-level get.

Verification

  • New test in test/capture_images_test.dart, "downloads and URL refreshes share a client nothing closes early": a client that, like BrowserClient, refuses requests after close() serves three images (fast, slow, and one whose URL is expired and gets refreshed). All three resolve.
    • I put the old behaviour back temporarily and confirmed the test fails, then restored the fix.
  • The full flutter test passes (1333, 5 skipped), and the analyzer is clean.
  • Real browser: in headless Edge (dart2js build, the real BrowserClient), three cloud images resolve through one capture client, including one refreshed after a 404. The screenshot and both video presets still pass.
  • Review: Codex Astra checked it statically and found nothing blocking. No runWithClient remains anywhere in lib/.

🤖 Generated with Claude Code

RetriggerConfidence Score: 5/5

No blocking issues found; safe to merge.

What we checked:

  • Exercised simultaneous fast and slow image downloads and a signed-URL refresh with a client that refuses requests after closure, and observed that with the explicit client handoff, all three images and the refresh completed before the client closed. T-Rex
  • Compared the top-level HTTP call path and the explicit client handoff path, and noted that the top-level path closed the client after the fast response while the explicit handoff allowed full completion before closing. T-Rex
  • Exercised a failed download and confirmed that capture cleanup closed the client and aborted the outstanding transfer. T-Rex
  • Ran the focused capture-image and page-screenshot tests; all 17 tests passed. T-Rex
  • Validated the non-2xx failure path described in the comparison, where the client closed and the remaining transfer was aborted, illustrating the early-close behavior and that this is not a run of the parent commit. T-Rex

Summary

The PR passes the capture-owned HTTP client to cloud image downloads so one completed request cannot close the client needed by another download or a signed-URL refresh. Focused checks completed concurrent downloads and a refresh, confirmed cleanup after a failed download, and passed all 17 capture-image and page-screenshot tests.

Reviews (1) · Last reviewed commit: "Keep a capture's shared download client ..."

A capture's downloads shared one client through http.runWithClient so a
failed capture could abort the rest. But package:http's top-level get
closes whatever client it picked up when its request finishes, so the
first finished download closed the shared client: in a browser that
aborts the other downloads in flight and refuses a refresh after an
expired URL, and a screenshot of a page with two or more cloud images
failed with "Couldn't load the images on this page."

The fetcher now receives the capture's client and downloadCloudImageBytes
calls client.get on it, so only the capture closes it, once it is done.
A test serves three images (one refreshed after an expired URL) through
a client that, like BrowserClient, refuses requests once closed; it
fails with the old behaviour.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 25383d3d-5385-4794-a32f-c711dbd8fcaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@SunkenInTime
SunkenInTime merged commit 9adbbe2 into icarus-cloud Sep 29, 2026
14 checks passed
SunkenInTime added a commit that referenced this pull request Sep 29, 2026
The fetcher now receives the capture's client (#232); passing it to
downloadCloudImageBytes keeps one finished download from closing it for
the rest.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

1 participant