Reproduces the Ivalua training-materials failure: the user clicks
Download on ivalua.docebosaas.com, a new tab opens,
and partway through it closes on its own. No file arrives.
/safeview-fileserv/ is never contacted, so the file is never
scanned -- the failure is before scanning, not during it.
From ivalua.docebosaas.com_mac_native.har (the native capture)
plus the TAB_open in the isolated captures, the click handler
is the common "open blank now, fill it in later" pattern:
win = window.open(''); // during the click, to beat the popup blocker
meta = await fetch('getCourseFile?file_id=1352&course_id=958'); // 356 ms
win.location = 'downloadCourseFile?course_id=958&file_id=1352&access_token=...';
// -> 302 -> 302 -> lmsfiles.s3.eu-west-1.amazonaws.com/....zip
// Content-Disposition: attachment
The two things that matter are that the new tab is opened blank and navigated later, and that its first and only navigation is the download. Every case below is a variation on one of those two properties.
Read this before trusting anything below. The first explanation attempted here has been tested and is wrong.
That theory was a race: the surrogate addresses download messages to the
download item's own WebContents, so they go out on the new tab's
tab_id channel, and at that moment the new tab's thin client is
still booting -- so registerNewDownload() never runs,
onDownloadStatusUpdated() early-returns on its
dl_prog guard, and /safeview-fileserv/ is never
contacted. It fitted the field logs and it fitted the SGH precedent.
The delay sweep in case 3 refutes it. Every delay from 0 ms
upward downloads correctly. If the fault were a race against the child's
bootstrap, 0 ms would be the worst case and would have to fail. It does not,
so the hand-off is reaching a live thin client and being handled. The two
surrogate mechanisms involved -- queue_download_updates_, armed
only by safeview_navigation_throttle.cc, and the SV-32430
opener retarget, gated on defer_initial_nav -- are real gaps in
the code, but they are not what breaks this flow.
getCourseFilesTree reports file_type: "archive").
Set a size and duration above and re-run.
*.amazonaws.com, a different site from
ivalua.docebosaas.com, and this tenant runs with
site_caps.site_isolation_r2 = true -- which is exactly the
switch that decides whether cross-site content moves to a separate
surrogate instance. Every run so far has been single-origin. Fill in a
second host above.
Those two are independent, so run them as a 2x2 rather than changing both at once. The tab lifetimes are the tell-tale: 5.7 / 6.2 / 6.1 s is a tight cluster, so whatever ends the tab is either a fixed timeout or a transfer of consistent length -- and only the size control can distinguish those.
| Claim | Evidence |
|---|---|
defer_initial_nav is false, so this is
not SV-33388/SV-32430 |
["TAB_open",6,"about:blank",false,"",false,false] on
the opener's websocket; argument order per
thin-client/tab.js onTabOpenRequest() |
| No popup modal, so no user-dwell delay (unlike the SGH case) | allow-tab-open sent 196 ms after TAB_open,
with prompted=false |
| The download was never announced on the opener's channel | Full opcode census of both isolated HARs: no
download_requested, no download_status_updated.
Only a client->surrogate dl-resume at startup |
| The download is attributed to a tab that never committed a document | surrogate-download-requested ... fsid=GssE1FVw-0,
where the opener's own session is GssE1FVw-25 |
| The child tab closed itself; the opener only reported it | Opener sends tab_close 6 5.7 s after opening, from the
win.closed poller at thin-client/tab.js:483-492 |
| NOT established: whether the child tab's thin client ever attached at all | The child tab's traffic is in its own DevTools session, which was not recorded. This is what the test below has to settle -- see "Capturing the child tab" |
/safeview-fileserv/ is reached at all.course_file_redirect.php,
get_course_file.php, attachment_csv.php --
into any folder on any PHP-capable server and open this page from
there. Every URL is built from this page's own location at runtime.
If you have a second server carrying the same files at the same directory
path, put its origin here (scheme + host, e.g.
https://other.example.com) and the last redirect will go there
instead, matching the
ivalua.docebosaas.com → *.amazonaws.com hop. The setting
is remembered in this browser.
The reported symptom is that the tab closes partway through the
download. A file that arrives instantly has no partway, so a small
attachment cannot express the failure at all and will pass every case here
no matter what else is wrong. The field file is a course archive
(file_type: "archive", a .zip), and the three
captured tabs lived 5.7 s, 6.2 s and 6.1 s before closing
-- so the defaults below aim at roughly that transfer time.
Size MB spread over ms
Set the duration to 0 to get the old instant-transfer
behaviour back for comparison. That comparison is itself a result: instant
passes but slow fails means the fault is in the teardown of a tab that is
still transferring, not in how the tab was opened.
The child tab closes itself, which is exactly why the field HARs are silent about it. Turn on DevTools → Settings → Preferences → Global → Auto-open DevTools for popups before clicking. The child gets its own DevTools window that survives long enough to read. What to look for, in order:
tc-kernel-min.js /
thin-client-min.js and open a
wss://.../r/websocket at all? If not, it never had a thin
client and the message had nobody to reach.surrogate-download-requested in the surrogate log.
The download landing first is the race./safeview-fileserv/. In the field, nothing was.
window.open('') during the click, a 356 ms metadata fetch, then
set the blank tab's location to a 2-redirect chain ending on an attachment.
This is the captured flow, hop for hop -- and fully cross-site too if you
filled in a second host above.
Expected failure: a new tab opens, sits blank, then
closes on its own. No file. No /safeview-fileserv/ request.
Identical, but the location is set in the same task as the
window.open. Separates "the app waits on an XHR" from "the tab
is opened blank".
If this fails too, the XHR gap is incidental and the blank-tab-plus-download shape is sufficient on its own.
The same flow at increasing metadata delays. A longer delay gives the child tab's thin client more time to finish booting before the surrogate starts the download.
This is the result that decides the diagnosis. A clean cutover -- short delays fail, long delays succeed -- proves it is a race against the child tab's thin-client bootstrap, and the crossover point is roughly how long that bootstrap takes. Failing at every delay means the child tab never gets a working thin client at all, and the fix has to be the opener retarget rather than any kind of waiting.
window.open(url) -- control
No blank tab. The URL is passed to window.open directly, so
TAB_open carries the real URL instead of
about:blank and the client navigates the child tab itself.
Expected pass. Also the smoke test -- if this fails, stop and fix the environment.
Blank tab and a metadata delay as in case 1, but the location is set straight to the attachment on this origin. Isolates the redirect chain and the cross-site final hop from the new-tab timing.
If both fail the same way as case 1, cross-site and redirects are not part of the cause and the new-tab hand-off is the whole story.
No new tab at all; navigate this tab to the same chain.
Expected pass. The opener has a live thin client, so the download is announced to somebody who is listening.
The child tab is watched with the same win.closed poll the thin
client uses, so its lifetime is recorded here even though it leaves no HAR
of its own. How long the child lived is the number to report
-- in the field captures it was 5.7 s and 6.2 s.