# 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.

Canonical: https://protocol.diverge.network/2.3.0/endpoints/images-oci/client/oci-blob/response/
Specification revision: 2.3.0

```text
[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`:

```rust
//! 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 })
    }
}
```
