Artifact d62d7bd753bf64f4fa8123310c7ac4d5035ae3e5277b96493e05f8c282c30ea0:
- File docs/rfcs/erratum/sync-protocol-00-s5.1-truncated-payload.md — part of check-in [44685f33b1] at 2026-10-12 18:45:05 on branch trunk — Fold the 23 errata into draft-fossil-{artifact-format,repo-state,sync-protocol}-01 (user: dmestas, size: 4228) [annotate] [blame] [check-ins using]
Erratum — draft-fossil-sync-protocol-00 §5.1
| Document | draft-fossil-sync-protocol-00 |
| Section | 5.1 — Message Structure (byte-counted payloads) |
| Type | Compatibility note (Fossil accepts a payload cut short by the end of the body; the draft's framing is kept and made explicit) |
| Status | Applied in draft-fossil-sync-protocol-01 (2026-10-12) |
| Reported | 2026-10-11 |
| Submitter | Dan Mestas |
| Found via | go-libfossil's conformance suite against Fossil 2.28 (scope note SP-5.1-1); confirmed by reading Fossil's source and by pushing it a short file card |
1. Summary
§5.1 says a byte-counted payload ends "only at the declared count", but says
nothing about a body that ends first. Fossil reads whatever bytes remain and
carries on. For a full-content file, those bytes are then hash-checked, so a
card that declares more bytes than the body holds is stored whenever the bytes
that are there hash to HASH.
2. Location
§5.1 (~lines 935-940):
Bodies are sequences of LF-terminated lines. Byte-counted payloads begin immediately after the line LF and may contain LF. They end only at the declared count. …
3. The divergence
Source, Fossil 2.28:
blob_extract()(src/blob.c:675-692) clamps the requested count to the bytes left in the input and returns the shorter blob; it reports the actual length but does not fail.xfer_accept_file()(src/xfer.c:160) ignores that return value. It hash-checks the extracted bytes (line 211) and stores them (line 214). Thecfilehandler (line 280) anduvfilehandler (line 349) extract the same way.
Run: a fossil new repository, nobody given gioz, sent through
fossil http as application/x-fossil-debug:
push 0000 PROJECTCODE
file 13febeeb…5615 1000
truncated payload test\n (23 bytes, then end of body)
The reply is # timestamp … errors 0, and blob holds 13febeeb… with size
- With bytes that do not hash to HASH, the request fails as any wrong-hash
filedoes.
4. Impact
- Integrity. None for
file: the hash check still decides what is stored, so nothing false is accepted. - Framing. A sender that miscounts can still get its last artifact stored by Fossil, and will be refused by a receiver that enforces the count. Seen from the sender, the two look inconsistent.
- Conformance. A test that a short payload is rejected fails against Fossil; go-libfossil leaves it out.
- Not checked here: truncated
cfileanduvfilepayloads, and truncated deltas. They take the same extraction path, but what happens next (decompression, delta application, UV hash checks) was not run.
5. Correction
State the rule the draft implies and record Fossil's leniency:
Bodies are sequences of LF-terminated lines. Byte-counted payloads
begin immediately after the line LF and may contain LF. They end
- only at the declared count. A cfile sender appends one further LF
+ only at the declared count. A body that ends before a payload's
+ declared count is malformed; senders MUST NOT produce one. (Fossil
+ instead uses the bytes that are present, and stores a full-content
+ file whose shorter payload still hashes to HASH.) A cfile sender
+ appends one further LF
6. Rationale
- The count is the frame. "End only at the declared count" already makes a short payload a framing error; saying so closes the gap the scope note found.
- No receiver requirement Fossil cannot meet. The sender rule is MUST NOT; receivers are told what Fossil does rather than being required to reject, so Fossil stays conforming and a strict receiver is not wrong.
- The hash makes the leniency safe, which is why a note is enough.
7. Verification
- Source: Fossil 2.28
src/blob.c:675-692(blob_extract);src/xfer.c:160,:211-214,:280,:349. - Run: the short
filecard in §3 against a fresh repository throughfossil http; stored with size 23 anderrors 0.
Prepared against draft-fossil-sync-protocol-00. The RFC remains the oracle;
the reference implementation is used only to confirm the observable behavior.