fetch: assure that the final flush packet is consumed after receiving a pack

The pack-writer perfectly consumes all input of the pack without
overshoot,  which it can as it knows how many objects it ought
to read.

Thus, the last packetline of the pack is consumed to the last
byte without ever asking for more data that would then be denied
as the flush packet is encountered.

This needs to be accounted for in the calling code.

Signed-off-by: Sebastian Thiel <sebastian.thiel@icloud.com>
This commit is contained in:
Sebastian Thiel 2023-11-12 09:47:36 +01:00 committed by cloudhead
parent 20a521179c
commit 4da63e97d1
No known key found for this signature in database
1 changed files with 20 additions and 29 deletions

View File

@ -12,7 +12,12 @@ use gix_protocol::{
handshake::{self, Ref},
ls_refs, FetchConnection,
};
use gix_transport::{bstr::BString, client, Protocol};
use gix_transport::{
bstr::BString,
client,
client::{ExtendedBufRead, MessageKind},
Protocol,
};
use super::{agent_name, indicate_end_of_interaction, Connection, WantsHaves};
@ -252,11 +257,24 @@ where
// needed as it needs `'static`. As the top-level seems to pass `Discard`,
// there should be no repercussions right now.
(&mut delegate).receive_pack(
reader,
&mut reader,
progress.add_child("receiving pack"),
&[],
&response,
)?;
assert_eq!(
reader.stopped_at(),
None,
"packs are read without 'overshooting', hence it never encountered EOF"
);
// Consume anything that might still be left on the wire - this is 'EOF' most of the time,
// but some tests have 'garbage' here as well.
std::io::copy(&mut reader, &mut std::io::sink())?;
assert_eq!(
reader.stopped_at(),
Some(MessageKind::Flush),
"the flush packet was now consumed"
);
break 'negotiation;
} else {
match action {
@ -271,33 +289,6 @@ where
indicate_end_of_interaction(&mut conn)?;
}
// N.b. the flush packet is never read in the packfile parser. To
// remedy this, we read from our connection until we see it ensure
// that there is no leftover data.
let (mut r, _) = conn.inner.into_inner();
let mut buf = [0; 4096];
loop {
match r.read(&mut buf)? {
0 => break,
n => match std::str::from_utf8(&buf[..n]) {
Ok(progress) => {
let lines = progress.split('\n');
if lines.into_iter().any(|line| line == "0000") {
break;
}
}
Err(e) => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("found leftover packfile bytes: {e}"),
)
.into());
}
},
}
}
log::trace!(target: "fetch", "fetched refs: {:?}", delegate.out.refs);
Ok(delegate.out)
}