Skip to content

Commit ca3afbf

Browse files
committed
fix(render-client): verify a first revision that ends with a lone CR
The parent writes `\n` before its update, so a first revision ending `%%EOF\r` is followed by `\r\n` in the sealed file, and its true end falls between the two. The client tried only the marker's end and the end of the whole end-of-line, and refused that seal as a protocol error. It now tries every end through the end-of-line. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
1 parent df3c12b commit ca3afbf

2 files changed

Lines changed: 18 additions & 5 deletions

File tree

‎crates/registry-render-client/src/lib.rs‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ fn bounded_version_and_warnings(document_type: &str, version: &str, warnings: &[
662662

663663
/// Whether `document_hex`, a lowercase hex SHA-256, is that of a prefix of
664664
/// `pdf` that ends at a `%%EOF` marker, optionally followed by its
665-
/// end-of-line. Found by byte search; the PDF is not parsed, so a marker
665+
/// end-of-line or the `\r` of a `\r\n`. Found by byte search; the PDF is not parsed, so a marker
666666
/// inside a stream is a candidate too. A prefix equal to the whole file is
667667
/// not a first revision.
668668
///
@@ -686,7 +686,9 @@ fn first_revision_matches(pdf: &[u8], document_hex: &str) -> bool {
686686
[b'\r' | b'\n', ..] => 1,
687687
_ => 0,
688688
};
689-
for end in [marker_end, marker_end + eol] {
689+
// Every end through the end-of-line: a first revision that ends
690+
// `%%EOF\r` is followed by the `\n` the update starts with.
691+
for end in marker_end..=marker_end + eol {
690692
if end >= pdf.len() {
691693
break;
692694
}
@@ -695,9 +697,6 @@ fn first_revision_matches(pdf: &[u8], document_hex: &str) -> bool {
695697
if running.clone().finalize().as_slice() == expected.as_slice() {
696698
return true;
697699
}
698-
if eol == 0 {
699-
break;
700-
}
701700
}
702701
}
703702
false

‎crates/registry-render-client/tests/seal.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,20 @@ async fn first_revision_hash_may_exclude_the_line_ending() {
322322
assert!(seal_with(200, body, None, None).await.is_ok());
323323
}
324324

325+
/// The parent writes `\n` before its update, so a first revision that ends
326+
/// `%%EOF\r` is followed by `\r\n` in the sealed file, and its hash ends
327+
/// between the two.
328+
#[tokio::test]
329+
async fn first_revision_hash_may_end_at_a_lone_carriage_return() {
330+
let first_revision = b"%PDF-1.7\n1 0 obj<<>>endobj\ntrailer<<>>\n%%EOF\r";
331+
let mut body = sealed_body_for(&[&first_revision[..], b"\n"].concat(), "B-B");
332+
body["documentDigest"] = json!(sha(first_revision));
333+
let sealed = seal_with(200, body, None, None)
334+
.await
335+
.expect("a first revision that ends with a carriage return");
336+
assert_eq!(sealed.pdf, [&first_revision[..], b"\n", UPDATE].concat());
337+
}
338+
325339
/// A stream may hold `%%EOF` as data, as a JPEG comment does, any number of
326340
/// times before the end marker of the first revision.
327341
#[tokio::test]

0 commit comments

Comments
 (0)