Summary
MCEF decides whether to download the JCEF runtime by comparing the complete bytes of the local and remote .sha256 files with FileUtils.contentEquals(...).
The checksum file currently served by the MCEF mirror is not a canonical checksum line. It is a 314-byte PowerShell Get-FileHash table containing headers, column padding, CRLF line endings, and the CI runner path:
Algorithm Hash Path
--------- ---- ----
SHA256 E98C385542620F31A594D6FC3C38ED6BCA8A547E24CED982A1339BB3333668BE D:\a\java-cef\java-cef\jcef_buil…
Only the 64-character hexadecimal value represents the archive checksum. Any change to the table formatting, runner path, padding, or line endings causes the complete-file comparison to fail and triggers a full JCEF download even when the semantic SHA-256 value has not changed.
This behavior is present in every maintained branch from 1.20.1 through 1.21.5, including the current default branch 1.21.4.
Impact
For mcef-forge-2.1.6-1.20.1, a checksum mismatch downloads windows_amd64.tar.gz again and extracts it. The archive currently served for the pinned java-cef commit is:
- Size:
124309275 bytes (118.6 MiB)
- SHA-256:
E98C385542620F31A594D6FC3C38ED6BCA8A547E24CED982A1339BB3333668BE
I downloaded the archive independently and calculated the same SHA-256, so the current archive and the semantic value in the checksum file are consistent. The problem is that non-semantic formatting bytes participate in the update decision.
The impact is amplified because CefDownloadMixin calls extractJavaCefBuild(true), which deletes the downloaded archive after extraction. A false mismatch therefore causes another complete 118.6 MiB transfer rather than reusing a local archive.
Potentially related reports include #79, #95, #109, #117, #137, and #141.
Relevant code
In MCEFDownloader.downloadJavaCefChecksum():
boolean sameContent = FileUtils.contentEquals(jcefBuildHashFile, jcefBuildHashFileTemp);
On mismatch, the downloaded temporary file is used as the new marker:
jcefBuildHashFileTemp.renameTo(jcefBuildHashFile);
return false;
The current implementation also does not validate that the remote response contains a SHA-256 value before replacing the marker, and does not check the result of renameTo(...).
Expected behavior
- Parse and compare the semantic 64-character SHA-256 value instead of comparing the complete checksum-file representation.
- Reject malformed or truncated remote checksum content.
- Do not replace a valid local marker when the newly downloaded checksum cannot be parsed.
- Continue requesting a JCEF download when the actual semantic SHA-256 value changes.
Proposed scope
A small first fix can be limited to MCEFDownloader:
- Extract exactly one SHA-256 token from each checksum file.
- Compare the normalized hexadecimal values.
- Throw an
IOException for malformed remote checksum content before replacing the existing marker.
- Replace the marker only after a valid semantic checksum has been obtained.
Archive caching, resumable downloads, locking, and library-path changes can be handled separately.
Summary
MCEF decides whether to download the JCEF runtime by comparing the complete bytes of the local and remote
.sha256files withFileUtils.contentEquals(...).The checksum file currently served by the MCEF mirror is not a canonical checksum line. It is a 314-byte PowerShell
Get-FileHashtable containing headers, column padding, CRLF line endings, and the CI runner path:Only the 64-character hexadecimal value represents the archive checksum. Any change to the table formatting, runner path, padding, or line endings causes the complete-file comparison to fail and triggers a full JCEF download even when the semantic SHA-256 value has not changed.
This behavior is present in every maintained branch from
1.20.1through1.21.5, including the current default branch1.21.4.Impact
For
mcef-forge-2.1.6-1.20.1, a checksum mismatch downloadswindows_amd64.tar.gzagain and extracts it. The archive currently served for the pinned java-cef commit is:124309275bytes (118.6 MiB)E98C385542620F31A594D6FC3C38ED6BCA8A547E24CED982A1339BB3333668BEI downloaded the archive independently and calculated the same SHA-256, so the current archive and the semantic value in the checksum file are consistent. The problem is that non-semantic formatting bytes participate in the update decision.
The impact is amplified because
CefDownloadMixincallsextractJavaCefBuild(true), which deletes the downloaded archive after extraction. A false mismatch therefore causes another complete 118.6 MiB transfer rather than reusing a local archive.Potentially related reports include #79, #95, #109, #117, #137, and #141.
Relevant code
In
MCEFDownloader.downloadJavaCefChecksum():On mismatch, the downloaded temporary file is used as the new marker:
The current implementation also does not validate that the remote response contains a SHA-256 value before replacing the marker, and does not check the result of
renameTo(...).Expected behavior
Proposed scope
A small first fix can be limited to
MCEFDownloader:IOExceptionfor malformed remote checksum content before replacing the existing marker.Archive caching, resumable downloads, locking, and library-path changes can be handled separately.