A picked profile photo is frozen into memory at selection time (v7.206.2) - #1256
Merged
Conversation
…6.2) Issue #1227, round 2: with the fileless fallback live, the member's photo upload still 400ed - the capture shows multipart submits with Content-Length: 0 from Safari AND the DuckDuckGo browser for macOS, which share the same system WebKit. Meanwhile another member's iPhone on the identical WebKit version saved fine via the urlencoded fallback, so the engine version is not the culprit; the multipart file stream is. WebKit streams a picked file from disk only when the form is sent, and a photo picked from the Photos media library is a temporary export that can vanish while the member sits in the crop dialog and the rest of the form - the body stream then aborts and the browser submits zero bytes. So the crop enhancement now copies the picked file into an in-memory File at selection time, when the bytes are provably readable (the crop dialog reads them too), and swaps it into the input via DataTransfer. An in-memory File is serialized from RAM and cannot vanish before send. Guarded by object identity against a quick re-pick, capped at 32 MB, and a failed read leaves the plain upload in place as before. No server changes. Smoke-tested end to end in a real browser: the frozen file arrives as a %Plug.Upload{} through the unchanged multipart path, crop fractions intact, and the avatar stores. An AI agent wrote this text in my name, unreviewed by me. The work behind it is mine; I only delegated the writing. Claude-Session: https://claude.ai/code/session_014ksBm1P9qsazixAHFeHwMc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Round 2 of #1227 (do not auto-close; the member confirms first).
What the capture showed after v7.206.1. The member's photo upload still 400ed: multipart submits with
Content-Length: 0, from Safari and from the DuckDuckGo browser for macOS — which is WKWebView, i.e. the same system WebKit (605.1.15/26.5.2). Minutes earlier another member's iPhone on the identical WebKit version saved fine through the new urlencoded fallback. So the engine version is innocent; the multipart file stream on his Mac is what dies. Both post-fix attempts were multipart, meaning a file was selected — consistent with his comment ("Profilbild-Upload lässt sich nicht speichern").The mechanism this targets. WebKit streams a picked file from disk only at send time. A photo picked from the Photos media library in the file dialog is a temporary export, and by the time the member has been through the crop dialog and the rest of the form it can be gone — the body stream aborts and the browser sends zero bytes. That explains a deterministic failure on his machine across both WebKit browsers while Chrome users upload fine.
The fix.
image_crop.jsnow freezes the picked file at selection time — reads the bytes (they are provably readable then; the crop dialog reads them too) into an in-memoryFileand swaps it into the input viaDataTransfer. An in-memory file is serialized from RAM and cannot vanish before send. Identity-guarded against a quick re-pick, capped at 32 MB, and a failed read leaves the plain upload in place exactly as before. No server changes.Verified in a real browser against a dev server: pick → freeze (
data-frozen-pickset, new File object, same bytes) → crop dialog → real submit → the server logs a genuine%Plug.Upload{}with the crop fractions and the avatar stores.mix precommitgreen (6,240 tests).An AI agent wrote this text in my name, unreviewed by me. The work behind it is mine; I only delegated the writing.
https://claude.ai/code/session_014ksBm1P9qsazixAHFeHwMc