Repository navigation
cmux-next browser: a web .mp4 sent as a generic file plays in the tab instead of downloading - #24338
Conversation
…he WebKit tab (fails: it downloads) Leo-ask: ask-76f83a7020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-98cd-7a42-ac32-a70f43729c15&host=cosmic-gray
…bKit tab instead of downloading raw.githubusercontent.com sends every .mp4 as application/octet-stream with nosniff (the What's New nightly reel among them), which WebKit cannot show, so the tab downloaded it. A main-frame response that would download, is not an attachment, and names a video (mp4, m4v, mov, webm, ogv) now loads a player page at the video's own address instead. Leo-ask: ask-76f83a7020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-98cd-7a42-ac32-a70f43729c15&host=cosmic-gray
…ck list loadHTMLString loads hidden from session history, so Back skipped the page the video was opened from (independent review). loadSimulatedRequest makes a normal history entry at the video's address. The test now goes a, b, then the video, waits for the video's time to advance, and checks Back and Forward; it holds its engine and writes the fixture off the main actor. Leo-ask: ask-76f83a7020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-98cd-7a42-ac32-a70f43729c15&host=cosmic-gray
… video player A POST's video cannot be fetched again by the player, and a traversal to an evicted entry must not push a new one; both keep downloading as before (independent review). The test checks the exact back list after Back and Forward, that a posted video downloads into a temporary folder, and writes its fixture on a background executor (@Concurrent). Leo-ask: ask-76f83a7020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-98cd-7a42-ac32-a70f43729c15&host=cosmic-gray
|
Owned by browser-import-2 on cosmic-gray · session |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: |
|
Found 9 test failures on Blacksmith runners: Failures
|
|
Bead |
…owed main-frame load A target=_blank click's action (no target frame) set the flag while a POST was still loading, so the POST's video could become the player (independent review). The flag is now set only when this view's own main-frame load is allowed. The test counts only a download the gate let start, and removes its folder off the main actor. Leo-ask: ask-76f83a7020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-98cd-7a42-ac32-a70f43729c15&host=cosmic-gray
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
… navigation plays The flag was written from the certificate recheck's late callback, so an older held GET could mark a newer POST's response playable (independent review). The tab now records, synchronously, the video URL the newest own main-frame navigation asks for, and only a response for that URL becomes the player. Leo-ask: ask-76f83a7020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-98cd-7a42-ac32-a70f43729c15&host=cosmic-gray
|
Review (independent subagent): SHIP at 5ff010c Reviewer: Codex gpt-6.1-sol on cmux16 (a different model from this lane), adversarial, fifth round. Rounds 1-4 blocked and each finding was fixed in a following commit: hidden history entry, POST responses, new-window actions, a late certificate-admission callback. VerdictSHIP at 5ff010c No blocking findings in manaflow-ai/cmux, browser-import-2/remote-video-plays against feat-cmux-next.
The main-frame, method, traversal, and response-URL guards do not reveal a remaining wrong-response conversion. Explicit downloads and synchronous cancellation paths precede player eligibility; organization filtering and certificate admission still precede the original load. The generated title and double-quoted source escape HTML delimiters, and the source is restricted to HTTP(S). Bypassing automatic-download admission here renders media rather than creating a download. Reviewed the complete patch and complete changed files fetched with curl at the exact head above. Static review only: no checkout, clone, build, tests, or gh operations; no runtime or CI success claimed. Tests (fleet,
|
|
Shipped in:
|
|
Shipped in:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Ready: an independent Codex review says SHIP at the head, and the fleet tests pass at the head and fail at the test-only commit (see the receipt comment).
Leo-ask: ask-76f83a7020
What
This PR handles the ".mp4 in cmux" half of the ask. The link to the What's New reel (
Watch what changed in nightly <sha> ↗) points atraw.githubusercontent.com/.../reel.mp4. GitHub sends every .mp4 there asapplication/octet-streamwithnosniff, so a cmux browser tab downloaded the file instead of playing it. Any other web .mp4 served the same way did too.Now a WebKit tab plays such a video at the video's own address, in a plain
<video controls autoplay>page (black background, fitted to the tab), when a main-frame response meets all of these:Content-Disposition: attachment;The page loads with
loadSimulatedRequest, so it is a normal back-list entry: Back returns to the page the video was opened from.These cases still download, as before:
The link's look ("this watch is kind aass") is the What's New page, which the whats-new lane owns. I've sent them that half of the ask, with the screenshot.
Known limitation
A page that calls
location.replace()on such a video gets a new back-list entry instead of replacing its own, because WebKit doesn't tell the app that a navigation is a replace. This is rare, and the player still plays.Chromium tabs don't take this path. CEF downloads octet-stream responses in the shim, and changing that means a shim rebuild. This PR keeps to the WebKit change.
Tests
Tests/CmuxNextBrowserTests/RemoteVideoPageTests.swiftruns a real WebKit tab against a local server. The server sends a generated H.264 .mp4 the way GitHub does:application/octet-stream,nosniff, with byte ranges. The test:currentTimeto pass 0;a, b, reel.mp4after Back and Forward;Observed / Not run
RemoteVideoPageTestspasses at the head (5ff010c).Changelog
No capture: the player is the system
<video>control on black. The test proves playback.Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Plays web videos whose servers send them as generic files in a cmux WebKit tab instead of downloading them — the nightly What's New reel among them, since
raw.githubusercontent.comserves every .mp4 asapplication/octet-streamwithnosniff. The video now opens in a plain player page (system controls, black background) at its own address, and takes a normal spot in the back list: Back returns to the page the video was opened from.Only a main-frame GET for an http(s) URL ending in mp4, m4v, mov, webm, or ogv becomes the player. The tab records the video URL when its newest own main-frame navigation asks for it, and only a response for that URL plays — a
target=_blankclick, an older held GET, or an in-flight reload cannot turn a POST's response into it. Attachments, other file types, POSTs, and Back or Forward navigations still download as before, as do Chromium tabs.Known limitation
location.replace()on such a video adds a new back-list entry instead of replacing its own; the player still plays.Tests
RemoteVideoPageTestsplays a generated H.264 .mp4 served like GitHub does (octet-stream, nosniff, byte ranges) and checks playback, the back-list order, that a form POST still downloads, and that only the matching response becomes the player.Written for commit 5ff010c. Summary will update on new commits.