Response
The server answers with the bytes of the blob in zero or more channel responses, each a piece in order, and the channel response finish; a finish with nothing before it states that the server does not hold the digest for the client.
[bytes …] zero or more, the blob
- The sequence. Zero or more channel responses, each a piece of the blob verbatim with no tag and no header, in order; the pieces concatenated are the blob. The channel response finish follows the last. A channel response finish that no channel response precedes states that the server does not hold the digest for the client.
- The pieces. The server sends no piece larger than 2 MiB. A client appends each piece to what arrived before and measures nothing; the finish says the blob is whole, and a channel that closes without its finish states that the blob did not all arrive.
The channel response is defined by diverge-sdk-rs/src/shared/containers/oci/blob/response/frame.rs:
//! One chunk of the blob being fetched.
use std::convert::Infallible;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
/// A piece of the blob's bytes, verbatim — no header, no tag: the
/// request named ONE blob, so there is nothing a frame could need to
/// say beyond the bytes themselves.
///
/// Borrowed from the frame it arrived in: the receiver is about to
/// hand these bytes on, and copying them first would double every
/// chunk's memory for nothing.
///
/// # Every frame appends
///
/// The receiver is chunk-naive by design: each frame's bytes are
/// concatenated onto what arrived before, and the channel's finish is
/// what says the blob is whole. The SENDER splits at
/// [`CHUNK_SIZE`](crate::CHUNK_SIZE); the receiver never measures.
/// Zero frames before the finish is the caller saying it does not
/// hold the digest at all.
///
/// # A short blob is detectable, and that is enough
///
/// A caller that dies mid-blob leaves the provider with bytes and a
/// finish it cannot tell from completion. No frame says "last one" —
/// the digest does: the provider hashes what arrived, and a partial
/// blob fails it, and is never served as the blob.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Frame<'a> {
/// The bytes, borrowed from the frame they arrived in.
pub body: &'a [u8],
}
impl Encode for Frame<'_> {
/// Bytes copied to bytes: nothing to fail.
type Error = Infallible;
fn encode(&self, out: &mut Writer<'_>) -> Result<(), Infallible> {
out.extend_from_slice(self.body);
Ok(())
}
}
impl<'a> Decode<'a> for Frame<'a> {
/// Bytes taken as bytes: nothing to fail.
type Error = Infallible;
fn decode(bytes: &'a [u8]) -> Result<Self, Infallible> {
Ok(Frame { body: bytes })
}
}